--- title: "Click to Source: Embedding Runtime Locations" date: "2025-10-20" draft: false --- # Click to Source: Embedding Runtime Locations {% internal_meta(title="Anchors") %} - Anchors Build-time transforms inject source locations into runtime code. Alt+Click any element to jump to its source file. ## Try It --- ## React Component Locations Transform `$` prop shorthand into `data-loc` attributes: ```typescript if (path.endsWith(".tsx")) { for (const match of code.matchAll(CLASSNAME_$_RE)) { const index = match.index!; const [_, pre, post] = match; let dataAttrs = ""; if (enableReact$Loc) { const { line, column } = indexToLineAndColumn(code, index + pre.length); const link = `${linkPath}:${line}:${column}`; dataAttrs = `data-loc=${JSON.stringify(link)}`; if (pre.startsWith("<") && !pre.startsWith("Content // Output (at build): Content ``` Runtime handler walks React fiber tree and opens the file: ```typescript const getPath = (fiber: Fiber, element: HTMLElement | undefined): string | undefined => { // First check for data-loc attribute if element is provided if (element?.dataset.loc) { return element.dataset.loc; } const source = fiber._debugSource ?? fiber._debugInfo ?? fiber._source; if (!source) return undefined; const { fileName, lineNumber = 1, columnNumber = 1 } = source; return `${fileName}:${lineNumber}:${columnNumber}`; }; const getLayersForElement = (element: HTMLElement, root: string): ComponentLayer[] => { let instance = getReactInstanceForElement(element); const layers: ComponentLayer[] = []; while (instance) { // Try to find the DOM element for this fiber to check for data-loc const fiberElement = instance.stateNode instanceof HTMLElement ? instance.stateNode : undefined; const path = getPath(instance, fiberElement); if (path) { const name = typeof instance.type === "string" ? instance.type : (instance.type.displayName ?? instance.type.name ?? instance.type.render?.name ?? "undefined"); layers.push({ name, path: path.replace(`${root}/`, "") }); } instance = instance._debugOwner ?? undefined; } return layers; }; ``` ## DevString Locations Tagged templates automatically capture call-site locations: ```typescript if (enableDevLoc) { for (const match of code.matchAll(DEV_RE)) { const index = match.index!; const { line, column } = indexToLineAndColumn(code, index); const [_, fn, message] = match; const link = `${linkPath}:${line}:${column}`; string.overwrite(index, index + _.length, `${fn}\`${message}\`.ctx({ loc: ${JSON.stringify(link)} })`); } } ``` ```typescript // Input: handler(dev`User pressed X`); // Output (at build): handler(dev`User pressed X`.ctx({ loc: "Card.tsx:83:12" })); ``` **Usage:** ```typescript function deleteCard(reason: DevString) { console.log("Called from:", reason.toJSON().context.loc); } deleteCard(dev`User clicked delete`); // Automatically knows source location ``` DevStrings compose with `.because()` to build audit trails: ```typescript const rootEvent = dev`keydown from root`; handler(rootEvent.because(dev`Looking for action handler`)); // Creates chain: "keydown from root → Looking for action handler" ``` ## Editor Integration Local HTTP endpoint opens files: ```typescript let lastOpenedFile: string | null = null; /** * uses our launch-editor endpoint to open the file in the dev's editor * this has been set up as a vite plugin. */ export const openInDevEditor = (loc: string) => { if (lastOpenedFile === loc) return; lastOpenedFile = loc; setTimeout(() => (lastOpenedFile = null), 500); void fetch(`http://localhost:5090/__open-in-editor?file=${loc}`).catch((error) => { console.error("Failed to open in editor", error); }); }; ``` ```typescript openInDevEditor("Card.tsx:26:7"); ↓ fetch("http://localhost:5090/__open-in-editor?file=Card.tsx:26:7"); ↓ // Editor opens at that line ``` ## Setup **Build plugin:** ```typescript import { bunDevStringAndReact$ClassNameLoc } from "./bun-dev-and-react-$-className-loc.mts"; await Bun.build({ plugins: [ bunDevStringAndReact$ClassNameLoc({ enableReact$Loc: true, enableDevLoc: true, }), ], }); ``` **Runtime:** ```typescript import { initClickToSource } from "./click-to-source.client.ts"; if (import.meta.env.DEV) { initClickToSource(); } ```