Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/small-buttons-create.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/devtools': major
---

Add third-party Prefetch Heatmap plugin to marketplace registry(metadata-only)
29 changes: 29 additions & 0 deletions packages/devtools/src/tabs/plugin-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,35 @@ const PLUGIN_REGISTRY: Record<string, PluginMetadata> = {
// THIRD-PARTY PLUGINS - Examples
// ==========================================
// External contributors can add their plugins below!

// Dimano — Prefetch Heatmap for TanStack Router
'@dimano/ts-devtools-plugin-prefetch-heatmap': {
packageName: '@dimano/ts-devtools-plugin-prefetch-heatmap',
title: 'Prefetch Heatmap',
description:
'Visualize TanStack Router prefetch intent, hits, and waste with a color overlay and a live metrics panel.',
requires: {
packageName: '@tanstack/react-router',
minVersion: '1.0.0',
},
// default export registers the plugin
pluginImport: {
importName: 'default',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm did you test it, I can't remember if I added an edge case to cover the default import?

Copy link
Contributor Author

@dimitrianoudi dimitrianoudi Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I tested the default import path.

  • The plugin exports a default factory:
// src/index.tsx
export default registerPrefetchHeatmapPlugin;
export { registerPrefetchHeatmapPlugin }; // also exported as a named fallback
  • Package entry points resolve to dist/ with ESM exports:
{
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } }
}
  • I validated loading via dynamic import:
const mod = await import('@dimano/ts-devtools-plugin-prefetch-heatmap');
const factory =
  (mod as any).default ?? (mod as any).registerPrefetchHeatmapPlugin;
console.assert(typeof factory === 'function');
// factory({ registerPanel, subscribeToEvents, sendToPage })
  • The marketplace entry uses:

pluginImport: { importName: 'default', type: 'function' }

which works with the above.

If you have an edge case in the loader, this package also exposes the named export (registerPrefetchHeatmapPlugin) so you can switch importName to that without code changes on my side. I’m happy to flip the registry to the named import if you prefer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, what I meant is did you try clicking on "add to devtools", this would form something like:

import { default } from "your-package";

maybe it would be a better idea to change it to actually be the named export registerPrefetchHeatmapPlugin

type: 'function',
},
// helps the host match your plugin deterministically
pluginId: 'prefetch-heatmap',
// show a nice card in the marketplace
logoUrl:
'https://raw.githubusercontent.com/dimitrianoudi/tanstack-prefetch-heatmap/main/assets/prefetch-heatmap-card.png',
docsUrl:
'https://github.com/dimitrianoudi/tanstack-prefetch-heatmap#prefetch-heatmap-devtools-plugin',
repoUrl: 'https://github.com/dimitrianoudi/tanstack-prefetch-heatmap',
author: 'Dimitris Anoudis (@dimitrianoudi)',
framework: 'react',
isNew: true,
tags: ['Router', 'Prefetch', 'Analytics', 'Overlay', 'TanStack'],
},
}

/**
Expand Down