vite-plugin-source-locator
v1.6.0
Published
Dev-only Vite plugin: resolve UI elements to source context for IDEs and coding agents
Maintainers
Readme
vite-plugin-source-locator
Dev-only Vite plugin that resolves any rendered UI element back to its source and exposes that context to coding agents (or opens the file in your IDE). Drop-in for React apps.
UI → structured source context → any agent — not locked to a single editor.
Project Structure
├── src/
│ ├── vite/ # Vite plugin, Babel plugin, editor integration
│ ├── client/ # Browser overlay (pick / context / overlay)
│ │ ├── pick/ # controller, actions, events, select-bus
│ │ ├── context/ # LocatorContext, path, snapshot, prompts
│ │ └── overlay/ # badge, tooltip, styles
│ └── shared/ # Types, constants, theme utilities
├── playground/ # Local React demo for pick mode + dialog shield
├── tests/ # Mirrors src/ layout
├── dist/ # Build output (published to npm)
└── .github/ # CI workflowsInstall
npm install -D vite-plugin-source-locatorYou also need @vitejs/plugin-react (or another setup that runs the Babel plugin in dev).
Playground
Local demo app (builds the plugin, then starts Vite on port 5177):
npm run playgroundUse the Locator badge to pick elements. Open the dialog and pick while it is open — outside-click should not close it.
Usage
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { sourceLocator } from 'vite-plugin-source-locator/vite'
export default defineConfig({
plugins: [
react(),
sourceLocator(),
],
})No main.tsx wiring required. The plugin auto-injects the client overlay in dev.
Pick Mode
- Click the badge (bottom-right): Locator
- Hover elements — blue highlight + file paths in tooltip
- Click to open the TSX source file in your IDE
- Shift+Click to copy a compact AI prompt; Alt/Option+Shift+Click for expanded (path / styles / box). On Mac the key is Option (⌥); on Windows/Linux it is Alt.
- Esc — cancel pick mode
| Shortcut | Action | |----------|--------| | Click | Open TSX source | | Shift+Click | Copy compact AI context | | Alt/Option+Shift+Click | Copy expanded AI context | | Esc | Cancel pick |
Dialog-safe picking
While pick mode is on, pointer events are stopped at the window capture phase so overlays from Radix, MUI, and similar libraries do not treat the pick click as an outside dismiss. You can open a modal, enable Locator, and jump to source without the dialog closing.
Exports
| Subpath | Purpose |
|---------|---------|
| vite-plugin-source-locator/vite | Vite plugin + sourceLocator.babel() |
| vite-plugin-source-locator/client | Overlay init, inspect / onSelect, context helpers |
| vite-plugin-source-locator/shared | Types, constants, parse/format utilities |
sourceLocator.babel()
For setups that need the data-source attribute injected directly through @vitejs/plugin-react's own babel config:
react({ babel: sourceLocator.babel() })This is fail-closed and development-only: it only registers the babel plugin when process.env.NODE_ENV === 'development'. Any other value (production, staging, unset, etc.) no-ops so absolute source paths never bake into shipped bundles. Vite's CLI sets NODE_ENV for both vite/vite dev and vite build; if you invoke Vite programmatically, set NODE_ENV to 'development' only for local serve.
Options
sourceLocator({
enabled: true,
endpoint: '/__open-in-editor',
attribute: 'data-source',
ides: ['auto', 'cursor', 'vscode', 'webstorm'],
theme: 'light',
})Theme
Control overlay colors (badge, tooltip, highlight). Presets or custom colors:
| Preset | Look |
|--------|------|
| 'default' | Dark slate + cyan accent |
| 'light' | White background + blue accent (also used when theme is omitted) |
| 'dark' | Black background + white/gray text |
| 'blue' | Navy background + light blue accent |
// preset
sourceLocator({ theme: 'light' })
// custom (merged over default)
import { initSourceLocator } from 'vite-plugin-source-locator/client'
initSourceLocator({
endpoint: '/__open-in-editor',
attribute: 'data-source',
theme: {
background: '#ffffff',
text: '#000000',
accent: '#2563eb',
},
})| Token | Used for |
|-------|----------|
| background | Badge & tooltip background |
| text | Tooltip text |
| accent | Borders, highlight, badge label |
MFE Safety
- Idempotent —
window.__sourceLocatorguard: multiple bundles loading the locator mount only one overlay - Shadow DOM — overlay styles isolated from host/MFE CSS
- Virtual module — client injected via
virtual:source-locator-client, works from any consuming app
Manual Init
import { initSourceLocator } from 'vite-plugin-source-locator/client'
const locator = initSourceLocator({
endpoint: '/__open-in-editor',
attribute: 'data-source',
theme: 'blue',
})
// Optional: hook selections for any agent / MCP adapter
locator?.onSelect((ctx, { action }) => {
console.log(action, ctx.source.file, ctx.source.line)
})
// Optional: inspect a DOM node programmatically (compact by default)
const context = locator?.inspect(document.querySelector('button')!)
// Expanded context (path, styles, box) for richer agent prompts
const expanded = locator?.inspect(document.querySelector('button')!, {
detail: 'expanded',
})Helpers for building / copying context without the overlay:
import {
getElementContext,
contextToPrompt,
copyContextForAI,
} from 'vite-plugin-source-locator/client'
const ctx = getElementContext(el, {
attribute: 'data-source',
detail: 'expanded',
})IDE Setup
On macOS, Cursor / VS Code open via cursor://file/… / vscode://file/… (Launch Services → existing window, no second Dock icon). Every other editor is spawned through its CLI with the goto-position flags from launch-editor's argument map (-r -g for the VS Code family, --line / --column for JetBrains IDEs, file:line:col for Sublime / Zed / Atom). An editor it does not know gets the file only.
Editor discovery still uses launch-editor's guess helper as a last resort. The open endpoint answers 500 when no editor can be resolved or the CLI fails to start, and the overlay shows Open failed.
Auto detection (default)
By default, ides includes 'auto' as the first entry. In auto mode, the plugin picks an editor in this order:
LAUNCH_EDITORenvironment variable (explicit override)- IDE-injected env (Cursor markers / VS Code NLS paths — not bare
VSCODE_PID, which forks also set) - The IDE that launched this Vite process (parent-process walk)
- Machine-wide detection via
launch-editorguess (running GUI editors /VISUAL— terminal editors likevimare ignored)
The plugin resolves known app-bundle CLI paths automatically (e.g. VS Code on macOS). If detection still fails, install the editor shell command or set LAUNCH_EDITOR to the full CLI path.
// auto-detect open IDE (default)
sourceLocator()
// VS Code only
sourceLocator({ ides: ['vscode'] })The ides option controls which editors the server may open. The browser client always sends ide=auto; the server resolves that via resolveIde against your ides list.
Explicit editor
When not using auto, the plugin resolves common install paths first, then falls back to the CLI name on PATH:
| IDE | CLI command |
|-----|-------------|
| Cursor | cursor |
| VS Code | code |
| WebStorm | webstorm |
If opening fails with ENOENT, install the shell command in your editor (VS Code: Shell Command: Install 'code' command in PATH) or set a full path:
LAUNCH_EDITOR=/Applications/Visual Studio Code.app/Contents/Resources/app/bin/codeAdding a New IDE
- Extend
LocatorIdeandIDE_ORDERinsrc/shared/index.ts - Use a launch-editor supported editor name as the new
LocatorIdevalue
Limitations
- Dev only — no production impact
- Files can be opened from the project root and any directory in Vite's
server.fs.allow(monorepo siblings included); anything else is refused with403 - JSX/TSX only for
data-sourceinjection - Expanded CSS path stops at mount ids
root/app(common React mounts); other app shells keep walking tobody - Expanded context does not include screenshots or React Fiber props
Contributing
See CONTRIBUTING.md for setup, scripts, PR workflow, and how to add a new IDE.
Changelog
1.6.0
- Fix: client script 404 when Vite
baseis not/ - Fix: absolute source paths under
/src(containerWORKDIR /src) were rewritten to<root>/src/src/… - Fix: non-VS Code editors (Sublime, Zed, JetBrains, …) received VS Code's
-r -gflags; arguments now come fromlaunch-editor - Fix:
vite-plugin-source-locator/clientcan be imported under SSR - Fix: files in Vite's
server.fs.allowdirectories (monorepo siblings) can be opened - Fix: the open endpoint reports
500when the editor fails to launch instead ofok - Fix: highlight follows the page on scroll/resize and survives the copy flash
- Fix: Windows paths show only the file name in the tooltip
- Fix: tooltip text no longer spills past the tooltip box, and the tooltip flips or pins to stay inside the viewport (phones, right and bottom edges)
- Privacy:
valueof text-like inputs is no longer copied into the AI prompt - Vite 7 added to the peer range
1.5.0
- UI context SDK: resolve UI → structured source context for any agent
- Shift+Click compact prompt; Alt/Option+Shift+Click expanded (path / styles / box)
- Public
inspect/onSelectAPI plusgetElementContext/contextToPrompt - Client layout:
pick/·context/·overlay/ - OS-aware shortcut labels (Option on Mac, Alt on Windows/Linux)
onSelect('open')fires only after a successful editor open
1.4.0
- Dialog-safe pick mode (capture-phase shield so modals stay open while picking)
- Local React playground (
npm run playground) - More reliable macOS / IDE CLI opening and parent-process detection
License
MIT
