Map the UI Tree to Source
At runtime a Lynx page is a tree of UI nodes: the elements the engine actually
rendered. The UI source map lets you take that runtime tree and map each
node back to the JSX that created it (repo, source, line, column).
It has three parts:
- Build: turn on
enableUiSourceMapso the build emits the UI source map intodebug-metadata.jsonand tags elements with anodeIndex. - Dump: ask the Lynx client to serialize the runtime UI tree as JSON.
- Remap: feed that JSON plus the
debug-metadata.jsontoremapUiTree, which annotates every node with its source location.
1. Enable it
UI source-map generation is off by default. Turn it on in pluginReactLynx:
With it on, the main-thread transform tags each created element with a
nodeIndex and records a nodeIndex → (source, line, column) table. That table
is emitted as the uiSourceMap field of debug-metadata.json:
For the runtime to point at this file you also need its debugMetadataUrl baked
into the template: that happens automatically against the dev server, and in
production you inject it yourself (see
Map Production Errors to Source → Model B).
Without it, the dumped nodes carry an empty debugMetadataUrl and can't be
resolved.
2. Dump the UI tree from the client
The API is the same on every platform: from a LynxView, asynchronously get the
root LynxElement, then call toJSONString on it to serialize the whole tree.
Both callbacks fire on the UI / main thread.
Each serialized node looks like this. The two fields remapping needs,
nodeIndex and debugMetadataUrl, are nested under debugInfo:
nodeIndex is the compile-time identity from step 1; debugMetadataUrl is the
URL baked into the template. Nodes without a debugInfo.nodeIndex (e.g. raw
text) simply won't be resolved.
3. Remap the tree
remapUiTree from
@lynx-js/debug-metadata
reads nodeIndex and
debugMetadataUrl at the top level of each node, while the engine nests them
under debugInfo, so hoist them up first, then remap. Its second argument is a
loader you supply that turns a debugMetadataUrl into its DebugMetadataAsset:
Every node whose nodeIndex is known to its debugMetadataUrl's uiSourceMap
gains repo / source / line / column; unresolvable nodes and all other
fields pass through unchanged. remapUiTree calls the loader once per distinct
debugMetadataUrl.
The npx @lynx-js/debug-metadata remap --ui <tree.json> CLI does the same, for a
tree whose nodes already carry top-level nodeIndex / debugMetadataUrl. The
lower-level buildUiSourceMapLookup (nodeIndex → location) and normalizeRepo
(git remote → owner/repo) helpers are exported too.