Skip to content

1. Installation

You want Xray in a dev build without teaching production about it. This chapter gives you the smallest honest setup: add the dev dependency, reserve the right-side host, wire the preload, and check that the panel opens.

Add The Dev Dependency

While re-frame2 is pre-alpha, use a checkout-local dependency from a dev alias:

;; deps.edn
{:aliases
 {:dev
  {:extra-deps
   {day8/re-frame2-xray {:local/root "tools/xray"}}}}}

When Xray is published, this becomes a normal Maven coordinate. Keep it in a dev-only alias. Xray is a tool, not application code.

Reserve The Host

Xray's normal launch mode is a true inline right rail. Your page owns the layout. Xray owns the content inside the host.

<div class="app-shell">
  <main id="app"></main>
  <aside data-rf-xray-host></aside>
</div>
:root { --rf-xray-accent: #7c5cff; }

.app-shell {
  display: flex;
  min-height: 100vh;
}

#app {
  flex: 1;
  min-width: 0;
}

[data-rf-xray-host] {
  flex: 0 0 var(--rf-xray-inline-width, 560px);
  min-width: 320px;
  box-sizing: border-box;
  border-left: 1px solid #2a2a2a;
}

The CSS variable sets the initial width. Xray adds its own drag handle, persists the user-chosen width, and yields if you deliberately put native resize: behavior on the host.

If your layout cannot use [data-rf-xray-host], configure another selector before rf/init!:

(require '[day8.re-frame2-xray.config :as xray-config])

(xray-config/configure!
  {:rf.xray/layout-host-selector "#devtools-xray"})

Wire The Preload

For a Shadow CLJS browser build:

;; shadow-cljs.edn
{:builds
 {:app
  {:devtools
   {:preloads [day8.re-frame2-xray.preload]}}}}

The preload registers Xray's trace and epoch collectors, installs the browser API, installs the Ctrl+Shift+C keybinding, and auto-opens into the layout host after the re-frame2 substrate adapter is ready.

You do not need to call init! when the preload is wired. day8.re-frame2-xray.core/init! exists for manual hosts and unusual embedding setups.

Launch And Close

In a normal dev page, Xray opens automatically once the app starts. The everyday controls are:

Action How
Hide or show Xray Ctrl+Shift+C
Close from the shell the close icon in the ribbon
Open from code (day8.re-frame2-xray.core/open!)
Toggle from code (day8.re-frame2-xray.core/toggle!)
Pop out to a second same-origin window (day8.re-frame2-xray.core/popout!)

Tool-owned pages can suppress only the automatic page-load open:

(xray-config/configure! {:rf.xray/auto-open? false})

That does not disable Xray. Explicit open!, toggle!, and the keybinding still work.

Check It

From this repository, the smallest useful Xray driving surface is the standard-epochs testbed:

cd implementation
npx shadow-cljs watch :examples/standard-epochs

Open http://localhost:8031. Click a few numbered buttons on the left. Xray should be visible on the right, and the event spine should fill with rows.

The standard-epochs app driving Xray

If Xray does not appear, check:

  • The host element exists in the page.
  • The preload is on the dev build, not the release build.
  • rf/init! has run with a substrate adapter.
  • window.day8.re_frame2_xray.status() has no missing-host diagnostic.

Clickable Jump-To-Source

Every panel that surfaces a source-coord wraps it in an open chip. Clicking jumps to that line in your editor — but only once Xray knows which editor to open. On a plain host app wiring just the preload, no editor is configured: the chip targets the :vscode default scheme, but if that is not your editor the OS has no handler for it and the click would silently go nowhere. So rather than navigate into the void, an unconfigured click surfaces a "No editor configured" hint — a small bottom-corner toast with an Open Settings button that lands you on the editor picker. Once an editor is configured (in Settings or at boot), the click resolves and navigates straight to source; the hint never fires.

Set your editor either in Xray Settings (the "Click-to-source links open in" picker on the General tab — persisted per-dev in localStorage, so each teammate can pick their own), or once at boot in code:

(require '[day8.re-frame2-xray.config :as xray-config])
(xray-config/configure! {:rf.xray/editor :cursor})
;; :vscode (default) | :cursor | :windsurf | :zed | :idea | {:custom "<uri-template>"}

The Settings picker overrides the boot-time configure! value per-machine, so a mixed-editor team sets a project default in code and individuals override locally.

:rf.xray/project-root is only needed when your stamped source-coords are classpath-relative (an editor cannot resolve a relative path). The normal reg-* / reg-machine registration path stamps absolute coords, which Xray ships verbatim — leave :rf.xray/project-root unset in that case. Do not hardcode a machine-specific path "to make Open work"; if absolute coords already open, you do not need it.

Production Posture

Production builds should not include the preload. Even if a dev-only path accidentally remains reachable, Xray's substrate is gated by re-frame2's debug flag and the bundle-isolation checks guard against Xray strings leaking into production bundles.

The practical rule is simple: put Xray in dev build config, not app code.