TanStack Devtools

repository·main·Indexed 19 days ago

https://github.com/tanstack/devtools

A unified debugging toolkit for inspecting and monitoring application state and behavior in real time. It integrates with the TanStack ecosystem and supports various frameworks, including React, Solid, and Angular.

Tokens
84.7K
Snippets
270
Records
353
Agent score
61%

What's inside TanStack Devtools

  1. Overview of TanStack Devtools

    main
    TanStack Devtools is a debugging toolkit designed to provide a unified interface for inspecting, monitoring, and extending applications. It allows developers to debug state and behavior in real time and features an extensible plugin architecture for customizable UIs. It is compatible with multiple frameworks including React, Solid, and Vanilla JS, and integrates seamlessly with other TanStack libraries like TanStack Query and TanStack Router.
  2. Overview of TanStack Devtools packages

    main

    TanStack Devtools is a framework-agnostic foundation for building and managing custom developer tools. It is organized into several layers, allowing you to install only what you need based on your use case.

    Framework Adapters

    Thin wrappers to integrate devtools into specific frameworks:

    • @tanstack/react-devtools
    • @tanstack/vue-devtools
    • @tanstack/solid-devtools
    • @tanstack/preact-devtools

    Core

    • @tanstack/devtools: The devtools shell UI (built in Solid.js). It provides the plugin system, tab navigation, settings panel, and the trigger button.

    Event System

    Used for communication between plugins and the shell:

    • @tanstack/devtools-event-client: A type-safe event client for building custom plugins.
    • @tanstack/devtools-event-bus: The WebSocket/SSE transport layer connecting the client and server.

    Build Tools

    • @tanstack/devtools-vite: A Vite plugin that provides source inspection, console piping, enhanced logging, and automatic stripping of devtools from production builds.

    Utilities

    • @tanstack/devtools-utils: Plugin factory helpers for each framework.
    • @tanstack/devtools-ui: A shared Solid.js UI component library.
    • @tanstack/devtools-client: Internal typed event client for core devtools operations.
  3. What is TanStack Devtools?

    main

    TanStack Devtools is a framework-agnostic toolkit designed for building custom developer tool panels. It uses a plugin system with typed event communication to provide a unified debugging experience across different frontend frameworks.

    Key components include:

    • Shell UI: The main container for devtools.
    • Event Transport: A system for moving data between the app and the devtools.
    • Framework Adapters: Specialized plugins for React, Vue, Solid, and Preact.
    • Build Tooling: Vite plugins for source injection and enhanced debugging.
  4. Key features of TanStack Devtools

    main

    TanStack Devtools provides several built-in capabilities for developers:

    • Framework Agnostic: Native support for React, Vue, Solid, and Preact.
    • Plugin System & Marketplace: A simple API to build, share, and install devtools plugins.
    • Type-Safe Event System: Fully typed communication between plugins and the shell.
    • Source Inspector: Enables "go-to-source" functionality by clicking elements in your app to jump to their source code.
    • Console Piping: Routes devtools output directly to the browser console.
    • Picture-in-Picture Mode: Allows the devtools panel to be popped out into a separate window to avoid obscuring the application UI.
    • Customizable Hotkeys: Supports rebinding keyboard shortcuts.
  5. Preact Framework Adapter Reference

    main

    The Preact adapter for TanStack Devtools provides utilities to integrate custom devtools panels into the TanStack Devtools ecosystem using Preact. It is functionally identical to the React adapter but uses preact JSX and preact/hooks.

    Key Differences from React

    • Import Path: Use @tanstack/devtools-utils/preact instead of @tanstack/devtools-utils/react.
    • JSX: Uses preact JSX runtime.
    • Hooks: Uses preact/hooks.
    • Attributes: While both work, it is idiomatic to use class instead of className in Preact.
    • Default Theme: If no theme is provided, the panel defaults to 'dark'.
  6. How TanStack Devtools production stripping works

    main

    TanStack Devtools uses two independent mechanisms to ensure devtools code is excluded from production bundles:

    1. Vite Plugin Auto-Stripping: For Vite projects, the @tanstack/devtools-vite plugin uses AST-based stripping. It parses source files and removes imports from devtools packages (e.g., @tanstack/react-devtools, @tanstack/devtools) along with any associated JSX elements. This happens automatically during vite build when the mode is production.

    2. Conditional Exports: The @tanstack/devtools core package uses Node.js conditional exports to serve different bundles. In a browser environment, it resolves to dev.js during development (including dev-only extras) and index.js for production builds.

  7. How event communication works in TanStack Devtools

    main

    The system relies on a typed event system for data flow between the application and the devtools panels.

    Core Concepts:

    • EventClient: The primary interface for plugins to emit and listen to events.
    • Bidirectional Communication: Supports commands, state editing, and time-travel debugging.
    • Serialization: All event payloads must be serializable. Use structuredClone for creating snapshots to ensure data integrity and avoid issues in cross-tab scenarios.
    • Event Naming: Do not include the pluginId prefix in your event names; the system handles namespacing internally.
    • Connection Lifecycle: Note that events may drop if the connection fails after 5 retries. Ensure you are listening for events after the connection is established.
  8. When to use factories vs manual plugin objects

    main

    Use Factories

    Use the factory functions (createReactPlugin, createVuePlugin, etc.) when building a reusable library plugin intended for publication. They provide:

    • Consistent plugin object shapes across frameworks.
    • Automatic generation of a matching NoOpPlugin for production tree-shaking.
    • Correct typing without manual annotations.

    Use Manual Plugin Objects

    Use manual objects when building a one-off internal devtools panel for your own application. This is simpler and avoids extra abstraction:

    // Manual approach for one-off panels
    {
      name: 'App State',
      render: (el, theme) => <MyPanel theme={theme} />,
    }
    // Manual approach -- fine for one-off panels
    {
      name: 'App State',
      render: (el, theme) => <MyPanel theme={theme} />,
    }
  9. How to build custom plugins and panels

    main

    Custom plugins are built by creating event clients and panel components that interact with the TanStack Devtools shell.

    Plugin Development Best Practices:

    • Event Clients: Use the EventClient class to manage the connection lifecycle and event maps. Ensure each plugin has a unique pluginId to avoid event collisions.
    • Panel Components: Build UI components that listen to events. Always respect the theme prop provided by the devtools to ensure visual consistency.
    • Cleanup: It is critical to clean up event listeners when a panel is unmounted to prevent memory leaks.
    • Limits: Be aware that there is a limit of 3 active plugins at a time.
    • Portals: Use framework-specific portals instead of raw DOM manipulation when rendering panel content.
  10. Create custom plugins using EventClient

    main

    TanStack Devtools allows you to create custom plugins by emitting and listening to an event bus. This is achieved using the @tanstack/devtools-event-client package. The process involves three main steps:

    1. Setup an EventClient: Define an EventMap where keys are event suffixes and values are the payload types. Extend the EventClient class and provide a pluginId in the constructor. The pluginId is automatically prepended to all event keys.
    2. Emit events from your application: In your application logic (e.g., a state manager or library), call DevtoolsEventClient.emit(eventSuffix, payload) whenever a state change occurs. The eventSuffix must match a key in your EventMap.
    3. Consume events in a Devtools Panel: Create a component that subscribes to the events using DevtoolsEventClient.on(eventSuffix, callback). The callback receives the payload.

    EventClient is framework-agnostic and works in vanilla JavaScript as well as React, Vue, or Angular.

    // 1. Setup
    type EventMap = {
      'counter-state': { count: number, history: number[] }
    }
    
    class CustomEventClient extends EventClient<EventMap> {
      constructor() {
        super({ pluginId: 'custom-devtools' })
      }
    }
    const DevtoolsEventClient = new CustomEventClient()
    
    // 2. Emit
    DevtoolsEventClient.emit('counter-state', { count: 1, history: [1] })
    
    // 3. Consume
    DevtoolsEventClient.on('counter-state', e => setState(e.payload))