Skip to content

@ereo/dev-inspector ​

Visual development tools and route inspector for EreoJS applications. Provides real-time insights into routes, data loading, islands, and caching during development.

Import ​

ts
// Core functions
import {
  createDevInspector,
  createDevToolsPlugin,
  generateInspectorHTML,
  createRouteInfo,
  formatRouteTree,
} from '@ereo/dev-inspector'

// DevTools tab components and generators
import {
  DevToolsPanel,
  generateDevToolsPanelHTML,
  DataPipelineTab,
  generateDataPipelineHTML,
  RoutesTab,
  generateRoutesTabHTML,
  IslandsTab,
  generateIslandsTabHTML,
  CacheTab,
  generateCacheTabHTML,
} from '@ereo/dev-inspector'

// Types
import type {
  InspectorConfig,
  RouteInfo,
  DevToolsConfig,
  DevToolsPanelData,
  DataPipelineVisualization,
  LoaderTiming,
  IslandVisualization,
  CacheVisualization,
  CacheEntry,
  RouteVisualization,
  HMREvent,
} from '@ereo/dev-inspector'

// WaterfallInfo is defined in @ereo/data (used by DataPipelineVisualization)
import type { WaterfallInfo } from '@ereo/data'

Overview ​

The @ereo/dev-inspector package provides two main features:

  1. Route Inspector - A simple route visualization tool mounted at a configurable path (default: /__ereo)
  2. DevTools Panel - A comprehensive browser-based developer panel with five tabs for routes, data pipeline, islands, cache, and HMR visualization (default: /__devtools)

Enabling the Inspector ​

Route Inspector Setup ​

ts
import { createApp } from '@ereo/core'
import { createDevInspector } from '@ereo/dev-inspector'

const app = createApp()

if (process.env.NODE_ENV === 'development') {
  app.use(createDevInspector())
}

Access at http://localhost:3000/__ereo

Custom Mount Path ​

ts
app.use(createDevInspector({
  mountPath: '/__routes'
}))

Full DevTools Panel ​

ts
import { createApp } from '@ereo/core'
import { createDevToolsPlugin } from '@ereo/dev-inspector'

const app = createApp()

if (process.env.NODE_ENV === 'development') {
  app.use(createDevToolsPlugin({
    mountPath: '/__devtools',
    dataPipeline: true,
    routes: true,
    islands: true,
    cache: true,
    position: 'bottom-right'
  }))
}

API Reference ​

createDevInspector ​

Creates a simple route inspector plugin.

Signature ​

ts
function createDevInspector(config?: InspectorConfig): Plugin

Configuration ​

ts
interface InspectorConfig {
  /** Path to mount inspector (default: '/__ereo') */
  mountPath?: string

  /** Enable route testing (reserved - not currently implemented) */
  enableTesting?: boolean

  /** Show loader data (reserved - not currently implemented) */
  showLoaderData?: boolean
}

Note: Only mountPath is currently functional. The enableTesting and showLoaderData options are defined for future implementation.

Plugin Behavior ​

The plugin:

  1. Registers a server middleware
  2. Serves HTML UI at the mount path
  3. Exposes a JSON API at {mountPath}/api/routes
  4. Logs the mount path to console on startup

createDevToolsPlugin ​

Creates the full DevTools panel plugin with all visualization features.

Signature ​

ts
function createDevToolsPlugin(config?: DevToolsConfig): Plugin

Configuration ​

ts
interface DevToolsConfig {
  /** Mount path for DevTools panel (default: '/__devtools') */
  mountPath?: string

  /** Enable data pipeline visualization (default: true) */
  dataPipeline?: boolean

  /** Enable routes visualization (default: true) */
  routes?: boolean

  /** Enable islands visualization (default: true) */
  islands?: boolean

  /** Enable cache visualization (default: true) */
  cache?: boolean

  /** Position of overlay toggle button (default: 'bottom-right') */
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
}

Example ​

ts
import { createDevToolsPlugin } from '@ereo/dev-inspector'

const devTools = createDevToolsPlugin({
  mountPath: '/__devtools',
  dataPipeline: true,
  routes: true,
  islands: true,
  cache: true,
  position: 'bottom-right'
})

Plugin Behavior ​

The plugin:

  1. Uses transformRoutes hook to collect route information
  2. Registers server middleware for DevTools endpoints
  3. Injects an overlay script into HTML responses
  4. Stores up to 100 pipeline metrics and HMR events
  5. Provides real-time metrics collection from route context

Features and Capabilities ​

Route Inspector (/__ereo) ​

The route inspector displays all registered routes with:

FeatureDescription
Route pathThe URL pattern
Render modeBadge showing SSR, SSG, CSR, API, or RSC
File locationSource file for the route
Feature tagsLoaders, actions, island counts, auth
StatisticsTotal routes, SSR count, SSG count, API count
SearchFilter routes by path (case-insensitive)

DevTools Panel Tabs ​

1. Data Pipeline Tab ​

The flagship feature for visualizing data loading performance:

FeatureDescription
Loader timelineVisual bars showing when each loader runs
Parallel efficiencyScore (0-100%) indicating parallelization
Waterfall detectionIdentifies unnecessary sequential patterns
Cache indicatorsShows cache hits vs fresh loads
Source iconsDatabase, API, Cache, or Compute sources
Total timeCombined request duration

Efficiency Score Thresholds:

  • Excellent (green): >= 80%
  • Good (blue): >= 50%
  • Fair (yellow): >= 30%
  • Poor (red): < 30%

Source Type Icons:

  • Database: Storage icon
  • API: Globe icon
  • Cache: Lightning bolt
  • Compute: Gear icon

2. Routes Tab ​

Interactive route exploration:

FeatureDescription
Route listAll routes sorted alphabetically
Search inputFilter routes by path
Filter buttonsQuick filter by render mode (All, SSR, SSG, API)
Feature tagsLoader, action, islands, auth, middleware counts
Timing displayLast request timing per route

3. Islands Tab ​

Component hydration visualization:

FeatureDescription
Island listAll hydrated islands on the page
Hydration statusHydrated or Pending indicator
Strategy breakdownCount by strategy (load, idle, visible, media)
Props sizeData size passed to each island
Hydration timeTime to hydrate (when available)
ActionsInspect, Scroll to island

Hydration Strategies:

  • load - Hydrate immediately on page load
  • idle - Hydrate during browser idle time
  • visible - Hydrate when scrolled into view
  • media - Hydrate based on media query match
  • none - Do not hydrate (static)

4. Cache Tab ​

Cache state and performance metrics:

FeatureDescription
Entry countTotal cached items
Total sizeMemory usage (formatted as B/KB/MB)
Hit rateOverall cache effectiveness (0-100%)
Entries viewList of cache keys with tags, size, TTL, hits
Tags viewStatistics grouped by cache tag
ActionsInvalidate by key, Invalidate by tag

Hit Rate Color Coding:

  • Excellent (green): >= 80%
  • Good (blue): >= 50%
  • Fair (yellow): >= 20%
  • Poor (red): < 20%

TTL Status Indicators:

  • Expired: Red
  • Expiring Soon (< 60 seconds): Yellow
  • Healthy: Green

5. HMR Tab ​

Hot Module Replacement event history:

FeatureDescription
Event listLast 50 HMR events (stores up to 100)
Connection statusShows if HMR is connected
Event typesfull-reload, css-update, island-update, loader-update, component-update
File pathWhich file triggered the update
DurationTime to apply the update
TimestampWhen the event occurred

Event Type Indicators:

  • Full Reload: Orange border
  • CSS Update: Green border
  • Island Update: Blue border
  • Loader Update: Purple border
  • Component Update: Pink border

API Endpoints ​

The DevTools plugin exposes the following HTTP endpoints:

EndpointMethodDescription
/__devtoolsGETDevTools panel HTML
/__devtools/api/routesGETJSON array of route data
/__devtools/api/pipelineGETJSON array of pipeline metrics history
/__devtools/api/hmrGETJSON array of HMR events
/__devtools/api/pipeline/recordPOSTRecord custom pipeline metrics

The Route Inspector exposes:

EndpointMethodDescription
/__ereoGETRoute inspector HTML
/__ereo/api/routesGETJSON array of routes

Recording Pipeline Metrics ​

ts
// POST to /__devtools/api/pipeline/record
fetch('/__devtools/api/pipeline/record', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    route: '/posts/123',
    totalTime: 45.2,
    loaders: [
      {
        key: 'getPost',
        start: 0,
        end: 20,
        duration: 20,
        cacheHit: false,
        source: 'db',
        waitingFor: []
      }
    ],
    efficiency: 0.85,
    waterfalls: [],
    timestamp: Date.now()
  })
})

Utility Functions ​

generateInspectorHTML ​

Generates the standalone route inspector HTML page.

ts
import { generateInspectorHTML } from '@ereo/dev-inspector'

const html = generateInspectorHTML([
  {
    id: 'home',
    path: '/',
    file: 'app/routes/index.tsx',
    renderMode: 'ssr',
    islandCount: 2,
    hasLoader: true,
    hasAction: false,
    middlewareCount: 0,
    authRequired: false
  }
])

createRouteInfo ​

Transforms framework routes into inspector-friendly format.

ts
import { createRouteInfo } from '@ereo/dev-inspector'

const routes = router.getRoutes()
const routeInfo = createRouteInfo(routes)

RouteInfo Interface ​

ts
interface RouteInfo {
  id: string
  path: string
  file: string
  renderMode: string
  islandCount: number
  hasLoader: boolean
  hasAction: boolean
  middlewareCount: number
  cacheTags?: string[]
  authRequired?: boolean
}

formatRouteTree ​

Formats routes for CLI display with icons.

ts
import { formatRouteTree, createRouteInfo } from '@ereo/dev-inspector'

const routes = router.getRoutes()
const routeInfo = createRouteInfo(routes)
console.log(formatRouteTree(routeInfo))

Output:

Route Tree:

  ⚡ / [loader]
     → app/routes/index.tsx
  📄 /about
     → app/routes/about.ssg.tsx
  🔌 /api/posts [loader, action]
     → app/routes/api/posts.api.ts
  🚀 /dashboard [auth, 3 islands]
     → app/routes/dashboard.tsx

Render Mode Icons:

IconMode
⚡SSR
📄SSG
💻CSR
🔌API
🚀RSC
•Unknown

generateDevToolsPanelHTML ​

Generates the complete DevTools panel HTML.

ts
import { generateDevToolsPanelHTML } from '@ereo/dev-inspector'
import type { DevToolsPanelData } from '@ereo/dev-inspector'

const data: DevToolsPanelData = {
  pipeline: { /* DataPipelineVisualization */ },
  routes: [/* RouteVisualization[] */],
  islands: [/* IslandVisualization[] */],
  cache: { /* CacheVisualization */ },
  hmrEvents: [/* HMREvent[] */]
}

const html = generateDevToolsPanelHTML(data)

Tab-Specific HTML Generators ​

For generating individual tab content:

ts
import {
  generateDataPipelineHTML,
  generateRoutesTabHTML,
  generateIslandsTabHTML,
  generateCacheTabHTML
} from '@ereo/dev-inspector'

// Each returns HTML string for that specific tab
const pipelineHtml = generateDataPipelineHTML(pipelineData)
const routesHtml = generateRoutesTabHTML(routesList)
const islandsHtml = generateIslandsTabHTML(islandsList)
const cacheHtml = generateCacheTabHTML(cacheData)

Type Definitions ​

DevToolsPanelData ​

ts
interface DevToolsPanelData {
  pipeline?: DataPipelineVisualization
  routes: RouteVisualization[]
  islands: IslandVisualization[]
  cache: CacheVisualization
  hmrEvents: HMREvent[]
}

DataPipelineVisualization ​

ts
interface DataPipelineVisualization {
  /** Route path */
  route: string
  /** Total execution time (ms) */
  totalTime: number
  /** Individual loader timings */
  loaders: LoaderTiming[]
  /** Parallel efficiency score (0-1) */
  efficiency: number
  /** Detected waterfalls */
  waterfalls: WaterfallInfo[]
  /** Timestamp of request */
  timestamp: number
}

LoaderTiming ​

ts
interface LoaderTiming {
  /** Loader key/name */
  key: string
  /** Start time relative to request start (ms) */
  start: number
  /** End time relative to request start (ms) */
  end: number
  /** Duration (ms) */
  duration: number
  /** Whether result came from cache */
  cacheHit: boolean
  /** Data source type */
  source: 'db' | 'api' | 'cache' | 'compute' | 'unknown'
  /** Loaders this was waiting for */
  waitingFor: string[]
  /** Data size in bytes (if available) */
  size?: number
}

WaterfallInfo ​

This type is imported from @ereo/data and used by DataPipelineVisualization to describe detected waterfall patterns in your data loading.

ts
// From @ereo/data
interface WaterfallInfo {
  /** The loader that waited */
  loader: string
  /** The loaders it waited for */
  waitedFor: string[]
  /** Whether the wait was necessary (e.g., the loader depends on data from the waited-for loaders) */
  necessary: boolean
  /** Suggestion for optimization (when the wait is unnecessary) */
  suggestion?: string
}

RouteVisualization ​

ts
interface RouteVisualization {
  /** Route path */
  path: string
  /** Route file */
  file: string
  /** Render mode */
  renderMode: 'ssr' | 'ssg' | 'csr' | 'api' | 'rsc'
  /** Has loader */
  hasLoader: boolean
  /** Has action */
  hasAction: boolean
  /** Middleware chain */
  middleware: string[]
  /** Island count */
  islandCount: number
  /** Cache tags */
  cacheTags: string[]
  /** Auth required */
  authRequired: boolean
  /** Last request timing (ms) */
  lastTiming?: number
}

IslandVisualization ​

ts
interface IslandVisualization {
  /** Island ID */
  id: string
  /** Component name */
  component: string
  /** Hydration strategy */
  strategy: 'load' | 'idle' | 'visible' | 'media' | 'none'
  /** Media query (if strategy is 'media') */
  mediaQuery?: string
  /** Whether island is currently hydrated */
  hydrated: boolean
  /** Time to hydration (ms) */
  hydrationTime?: number
  /** Props size in bytes */
  propsSize: number
  /** DOM element selector */
  selector: string
}

CacheVisualization ​

ts
interface CacheVisualization {
  /** Cache entries */
  entries: CacheEntry[]
  /** Total cache size (bytes) */
  totalSize: number
  /** Hit rate (0-1) */
  hitRate: number
  /** Cache stats by tag */
  tagStats: Map<string, { count: number; hits: number; misses: number }>
}

CacheEntry ​

ts
interface CacheEntry {
  /** Cache key */
  key: string
  /** Associated tags */
  tags: string[]
  /** Entry size in bytes */
  size: number
  /** Time to live remaining (ms) */
  ttl: number
  /** Created timestamp */
  created: number
  /** Last accessed timestamp */
  lastAccessed: number
  /** Access count */
  accessCount: number
}

HMREvent ​

ts
interface HMREvent {
  /** Event type */
  type: 'full-reload' | 'css-update' | 'island-update' | 'loader-update' | 'component-update'
  /** File path */
  path: string
  /** Reason for update type */
  reason?: string
  /** Timestamp */
  timestamp: number
  /** Duration (ms) */
  duration?: number
}

Client-Side API ​

When the DevTools panel is open, it exposes a global API:

ts
window.__EREO_DEVTOOLS__ = {
  refresh(): void           // Reload DevTools panel
  togglePosition(): void    // Toggle panel position
  close(): void             // Close DevTools panel
  highlightIslands(): void  // Highlight all islands on page
  hydrateAll(): void        // Force hydrate all islands (reserved)
  scrollToIsland(id): void  // Scroll to specific island
  inspectIsland(id): void   // Inspect island details (reserved)
  inspectEntry(key): void   // Inspect cache entry (reserved)
  clearCache(): void        // Clear all cache (reserved)
  refreshCache(): void      // Refresh cache view (reserved)
  invalidateKey(key): void  // Invalidate cache by key (reserved)
  invalidateTag(tag): void  // Invalidate cache by tag (reserved)
}

Note: Functions marked as "reserved" send messages but handlers are not fully implemented. They are reserved for future functionality.

Overlay Functionality ​

The DevTools overlay supports these interactive features via postMessage:

Message TypeDescription
ereo-devtools-closeClose the DevTools panel
ereo-devtools-toggle-positionToggle panel position
ereo-devtools-highlight-islandsHighlight all [data-island] elements for 3 seconds
ereo-devtools-scroll-to-islandScroll to and highlight a specific island

Integration Details ​

Pipeline Metrics Collection ​

The DevTools plugin automatically collects pipeline metrics when available in the request context:

ts
// The plugin reads from context:
const metrics = context.get<PipelineMetrics>('__pipeline_metrics')

This integrates with @ereo/data package which sets these metrics during loader execution.

History Limits ​

  • Pipeline metrics: Stores last 100 requests
  • HMR events: Stores last 100 events
  • Cache entries display: Shows top 50 by last accessed time
  • HMR events display: Shows last 50 events

Overlay Specifications ​

  • Button size: 48x48 pixels
  • Panel height: 400px (fixed)
  • Panel position: Docked to bottom of viewport
  • Z-index: Button 99998, Panel 99999

Performance Considerations ​

The DevTools plugin adds minimal overhead in development:

  • Route transformation runs once at startup via transformRoutes hook
  • Pipeline metrics are collected passively from context
  • The overlay script is approximately 2KB
  • API endpoints only process data when called
  • HTML responses are only modified when dataPipeline, islands, or cache options are enabled

Production Recommendation:

ts
import { createApp } from '@ereo/core'

const plugins = []

if (process.env.NODE_ENV === 'development') {
  const { createDevToolsPlugin } = await import('@ereo/dev-inspector')
  plugins.push(createDevToolsPlugin())
}

const app = createApp({ plugins })

Troubleshooting ​

DevTools Panel Not Appearing ​

  1. Verify the plugin is added to your config
  2. Check the console for the mount path message: DevTools available at /__devtools
  3. Ensure you're not in production mode
  4. Check if another middleware is intercepting the route

No Pipeline Data Showing ​

  1. Navigate to a route that has loaders
  2. Verify @ereo/data package is configured
  3. Check that loaders are setting __pipeline_metrics in context

Islands Not Detected ​

  1. Ensure islands use data-island attribute
  2. Check that the islands configuration is in route config
  3. Verify the page has completed loading

Routes Not Updating ​

  1. The plugin collects routes via transformRoutes which runs at startup
  2. Restart the dev server after adding new routes
  3. Check that routes are properly registered with the router

Released under the MIT License.