-
Notifications
You must be signed in to change notification settings - Fork 2
Debugging
Reflet provides a powerful visual debugger that is ideally suited to inspecting complex, data driven apps.
While tools like re-frame-10x
provide an excellent global lens into
your application, they are not ideal for graph data exploration. At
the same time, reducing the signal to noise ratio in a global lens can
sometimes be a challenge with large apps.
In contrast, the Reflet debugger immediately places you in the local context of your components, their data, and interdependencies. Understanding these connections comes naturally and intuitively from Reflet's design philosophy, where references connect everything together. References form the backbone of your API, and are the natural entry point for exploration.
Ultimately, this approach is meant to be complementary to, rather than replace other tools. For one thing, the Reflet debugger only handles graph data. But because both graph and non-graph data models can co-exists perfectly fine in a Reflet application, other tools are still indispensable.
The Reflet example client offers a working example of the debugger in action.
It should also be noted that the Reflet debugger was written entirely in Reflet, and demonstrates most of the features described in these documents in a real, complex use-case.
Your with-ref
component API is the entry point for debugging. The
Reflet debugger overlays this API directly on top of your application
in the browser, and you can toggle it on or off by pressing Ctrl + j
:
The hotkey character j
is configurable as described in the
Configuration document.
Each purple marker indicates a with-ref
at that point in the DOM
tree. Multiple overlapping with-ref
s are collected together into one
group marker:
Whether it is a single or group marker, mousing over it will open a
list of available with-ref
entry points. Clicking on an entry point
will open a with-ref
"props" panels:
This panel will show the props map of the with-ref
. The panel header
includes the component name, the component namespace, and the line
number of the with-ref
occurrence. Additionally, all debugger panels
are draggable, and can be minimized by double clicking on the header.
The props map in the content area will include:
- Any new refs that the
with-ref
created and added to props - Any refs that were passed in to the
with-ref
- Any additional prop values that were merged in
In this example, the props map includes 4 new refs that the with-ref
generated: :player/self
, :player/context
, :player/source
, and
:player/el
, and a 5th property, :app/self
, which was created by
another with-ref
in the parent reflet.client.ui/app
component.
Any refs that appear in the debugger are clickable. Most of them will appear in a condensed form, meaning that:
[:cmp/uuid #uuid "b235f3f6-f529-4dc3-8583-5289e4d93625"]
will be displayed using the last 8 characters of the UUID:
cmp@e4d93625
Note: obviously truncating the UUID in this way means it is possible that two unique UUIDs might be rendered to appear the same. However in practice, the productivity benefits that this condensed representation brings are substantial enough that they far outweigh the small chance of a conflict. Keep in mind that total number of UUIDs that will appear on screen during debugging at any one time is actually quite small.
If you want to see the fully expanded value of the reference, simply right-click on the ref to open a context menu:
Similarly you can right-click on any data value that is not a collection to see the full value in a context menu.
Left-clicking on any ref will open a "ref" panel, which immediately lets you choose from 4 available lenses for exploration: DB, EVENTS, QUERY, FSM:
There are also two special panel types that are available for the
unique attributes :js/uuid
and :el/uuid
. These unique attributes
are used for JS objects and DOM elements respectively. The current
implementation for these panels is still somewhat limited, but for now
they show whether a JS object has been initialized:
and a reactive serialization of the DOM element:
The DB lens shows the graph entity that is associated with that reference, as it appears in the Reflet db.
For example, the component local state of the
reflet.client.ui.player/player
component:
And the domain data associated with the "Orbits"
track:
Every collection type can be expanded vertically by left-clicking a toggle:
When nested collection is expanded horizontally within a panel, all entity references are clickable and will open to other panels.
However, you can also right-click on the collection toggle button top open a plain-text value of the collection for copy-pasting:
Finally, note the little sandwich menu icon in the top left corner of
the panel. Clicking on this will return you to the reference lens
menu, where you can choose another lens to explore. This sandwich icon
appears in all of the panels, except for the with-ref
props panel.
Any events that a reference participates in will show up in the event lens. A ref participates in events in two ways:
-
An entity associated with the ref was touched by a graph data operation as a result of the event
-
The ref was one of the positional arguments of the event (collection arguments are not checked recursively)
Each event trace in the lens has associated with it the db t
at
which the event occurred. This also corresponds with the t
given in
the query and FSM lenses. Recall from the Multi Model
DB document that this t
is monotonically
increasing, but not necessarily contiguous. It is normal to see
jumps in t
between events that may have happened sequentially. Do
not rely on t
increasing contiguously.
Any graph query that a reference participates in will show up in the query lens:
A ref participates in a query if it is reached at any point during query traversal. Every graph query that is reactive to changes in the entity associated with the reference will show up in the Query lens.
Each trace will list:
- The db
t
at which the query was last updated - The query vector of the invoking subscription
- The result of the query
Note that each trace provides a set of controls for navigating the
values of the query over time. The debugger will keep a history of
values determined by the Reflet configuration parameter
:trace-queue-size
, which defaults to 50 values.
For graph queries with a result function, the result function will show up as a separate trace, with a modified id in the query vector. For example, given a query vector:
[::query arg1 arg2]
The result query vector would be:
[::query[result-fn] arg1 arg2]
Every FSM currently running that is associated with the reference via
the :ref
identity, will appear in the FSM lens:
Each FSM trace will list:
- The db
t
at which the FSM last transitioned; the very first trace is not technically a transition, but an FSM initialization trace - The invoking FSM vector: this is either a subscription vector, or
the vector that was passed to the
::fsm/start
event - The transition FROM -> TO states
- A number of additional attributes that includes:
- The event that triggered the transition
- Then
:when
conditional clause, if provided - The
:pull
expression, if provided
As with the query traces, each FSM trace provides a set of controls
for navigating previous transitions of an FSM. Once again the number
of retained transitions is control by the :trace-queue-size
Reflet
configuration parameter.
There is a set of global controls that appear at the bottom of the browser window whenever the debugger overlay is active:
For now this area only hosts a button that closes all the overlay panels. However, this could potentially host future features such as:
-
Search for an explicit ref to open in a panel
-
Time travel controls as you get in
re-frame-10x
Note that activating or de-activating the debugger overlay only
toggles the purple with-ref
markers. In contrast, once open, the
debugger panels persist until closed.
Next: Testing
Home: Home