Trace the connections and flows between tapable hooks in real-time.
Collect structured stack traces, and optionally export them as UML diagrams.
Have you ever wondered what the internals of webpack look like?
Below is a UML-style representation of webpack's internal hooks captured at
runtime. This diagram was generated using the tapable-tracer and its
webpack plugin by
tracing dynamically every hook tap and call in the system.
View the full interactive version here:
- Real-time: Observe hooks as they're tapped and called.
- Structured: Frames represent a directed graph.
- Dynamic: No patching or rewriting needed.
- UML Export: Visualize traces via Mermaid diagrams.
- Configurable: Include or exclude the triggers.
- Customizable: Embed information to be visible on diagrams.
- Universal: Works with any tapable-based code, not just webpack.
yarn add tapable-tracerTo start tracing hooks, first create a tracer:
import { createTracer } from "tapable-tracer";
const tracer = createTracer();To capture hook activity, register each hook with the tracer:
import { traceHook } from "tapable-tracer";
traceHook(tracer, hook1);
traceHook(tracer, hook2);Export the captured frames as encodable array:
import { dumpStackTrace } from "tapable-tracer";
const frames = dumpStackTrace(tracer.trace);Generate a Mermaid-compatible diagram code:
import { generateMermaidUML } from "tapable-tracer/extensions/mermaid";
const uml = generateMermaidUML(frames);tapable-tracer exposes its own hooks (via tapable) for further
instrumentation:
- PreCallHook: Before a Tap.fncalled.
- PostCallHook: After a Tap.fncompletes.
- HandleStackFrameHook: When a new stack frame is emitted.
Pass TracerOptions to
createTracer():
The available options are:
- interceptorName (string): Name of the interceptor to use.
- labelHook (HookLabellerFunction): Function to label hooks.
- labelTap (TapLabellerFunction): Function to label taps.
Pass HookTracingOptions to
traceHook():
The available options are:
- includeTrigger (boolean): Whether to include the trigger in the trace.
- key (string): The hook's identifier in a container data-structure inside the system. Also used as the fallback label for the hook.
The tracer captures three different frame types:
- TapFrame: A tap is registered to a hook.
- TriggerFrame: A delegate is called before the actual- Tap.fn.
- CallFrame: A- Tap.fnis called.
Additionally, it uses a CallSite context
object per tap, for storing the hook, tap, and the original callback function.
To capture the frames the tracer uses two separate states:
- Stack: A stack of CallSiteobjects that represents the current call stack.
- Trace: A list of frames that represents the entire trace of the flows.
For tracing a hook, the tracer intercepts the hook's tap, call and loop
events.
When a tap is added:
- A CallSiteobject is created for further reference.
- A TapFrameis created and pushed onto thetracelist.
- The tap.fnfunction is overridden to capture the call events, by keeping theCallSiteobject in the closure.
When a call or loop event occurs:
- Create and push a TriggerFrameonto thetracelist, if theincludeTriggeroptions is set totruefor the hook and the call was caused by a tap.
- Push the CallSiteobject onto thestack.
- Execute the original callback function.
- Pop the CallSiteobject from thestack.
- Create and push a CallFrameonto thetracelist.
Example: Output without triggers
[
  { hook: 'hook1', tap: 'hook2', type: 'tap' },
  { hook: 'hook2', tap: 'hook3', type: 'tap' },
  { hook: 'hook3', tap: 'hook4', type: 'tap' },
  { callee: 'hook1', caller: null, type: 'call' },
  { callee: 'hook2', caller: 'hook1', type: 'call' },
  { callee: 'hook3', caller: 'hook2', type: 'call' },
  { callee: 'hook4', caller: 'hook3', type: 'call' }
]Example: Graph visualization of the output without triggers
Example: Output with triggers
[
  { hook: 'hook1', tap: 'Plugin2', type: 'tap' },
  { hook: 'hook2', tap: 'Plugin3', type: 'tap' },
  { hook: 'hook3', tap: 'Plugin4', type: 'tap' },
  { callee: 'hook1', caller: null, type: 'call' },
  { callee: 'Plugin2', caller: 'hook1', type: 'trigger' },
  { callee: 'hook2', caller: 'Plugin2', type: 'call' },
  { callee: 'Plugin3', caller: 'hook2', type: 'trigger' },
  { callee: 'hook3', caller: 'Plugin3', type: 'call' },
  { callee: 'Plugin4', caller: 'hook3', type: 'trigger' },
  { callee: 'hook4', caller: 'Plugin4', type: 'call' }
]Example: Graph visualization of the output with triggers
This project is licensed under the MIT License. See the LICENSE file for details.