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
6 changes: 6 additions & 0 deletions .changeset/good-guests-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@tanstack/devtools-vite': patch
'@tanstack/devtools': patch
---

Add go to source functionality to devtools
12 changes: 11 additions & 1 deletion docs/vite-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,14 @@ const open = (file: string, line: number) => {
enhancedLogs: {
enabled: true
}
}
}
```

## Features

### Go to source

Allows you to open the source location on anything in your browser by clicking on it.

To trigger this behavior you need the Devtools Vite plugin installed and configured and
the Panel available on the page. Simply click on any element while holding down the Shift and Ctrl (or Meta) keys.
3 changes: 2 additions & 1 deletion examples/react/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@vitejs/plugin-react": "^4.5.2",
"vite": "^7.0.6"
"vite": "^7.0.6",
"vite-plugin-inspect": "11.3.2"
},
"browserslist": {
"production": [
Expand Down
3 changes: 3 additions & 0 deletions examples/react/basic/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { devtools } from '@tanstack/devtools-vite'
import Inspect from 'vite-plugin-inspect'

// https://vite.dev/config/
export default defineConfig({
plugins: [
devtools(),
Inspect(),
react({
// babel: {
// plugins: [['babel-plugin-react-compiler', { target: '19' }]],
Expand Down
2 changes: 2 additions & 0 deletions examples/solid/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"solid-js": "^1.9.7"
},
"devDependencies": {
"@tanstack/devtools-vite": "0.2.3",
"vite": "^7.0.6",
"vite-plugin-inspect": "11.3.2",
"vite-plugin-solid": "^2.11.6"
},
"browserslist": {
Expand Down
4 changes: 2 additions & 2 deletions examples/solid/basic/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig } from 'vite'
import solid from 'vite-plugin-solid'

import { devtools } from '@tanstack/devtools-vite'
// https://vite.dev/config/
export default defineConfig({
plugins: [solid({})],
plugins: [devtools(), solid({})],
})
10 changes: 10 additions & 0 deletions packages/devtools-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,17 @@
"vite": "^7.0.0"
},
"dependencies": {
"@babel/core": "^7.28.3",
"@babel/generator": "^7.28.3",
"@babel/parser": "^7.28.3",
"@babel/traverse": "^7.28.3",
"@babel/types": "^7.28.2",
"@tanstack/devtools-event-bus": "workspace:*",
"chalk": "^5.6.0"
},
"devDependencies": {
"@types/babel__core": "^7.20.5",
"@types/babel__generator": "^7.27.0",
"@types/babel__traverse": "^7.28.0"
}
}
18 changes: 18 additions & 0 deletions packages/devtools-vite/src/babel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { parse } from '@babel/parser'
import * as t from '@babel/types'
import generate from '@babel/generator'
import traverse from '@babel/traverse'

export { parse, t }

export const trav =
typeof (traverse as any).default !== 'undefined'
? // eslint-disable-next-line @typescript-eslint/consistent-type-imports
((traverse as any).default as typeof import('@babel/traverse').default)
: traverse

export const gen =
typeof (generate as any).default !== 'undefined'
? // eslint-disable-next-line @typescript-eslint/consistent-type-imports
((generate as any).default as typeof import('@babel/generator').default)
: generate
52 changes: 52 additions & 0 deletions packages/devtools-vite/src/inject-source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { normalizePath } from 'vite'
import { gen, parse, t, trav } from './babel'
import type { types as Babel } from '@babel/core'
import type { ParseResult } from '@babel/parser'

const transform = (ast: ParseResult<Babel.File>, file: string) => {
let didTransform = false
trav(ast, {
JSXOpeningElement(path) {
const loc = path.node.loc
if (!loc) return
const line = loc.start.line
const column = loc.start.column

// Inject data-source as a string: "<file>:<line>:<column>"
path.node.attributes.push(
t.jsxAttribute(
t.jsxIdentifier('data-tsd-source'),
t.stringLiteral(`${file}:${line}:${column}`),
),
)

didTransform = true
},
})

return didTransform
}

export function addSourceToJsx(code: string, id: string) {
const [filePath] = id.split('?')
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
const location = filePath?.replace(normalizePath(process.cwd()), '')!

try {
const ast = parse(code, {
sourceType: 'module',
plugins: ['jsx', 'typescript'],
})
const didTransform = transform(ast, location)
if (!didTransform) {
return { code }
}
return gen(ast, {
sourceMaps: true,
filename: id,
sourceFileName: filePath,
})
} catch (e) {
return { code }
}
}
25 changes: 25 additions & 0 deletions packages/devtools-vite/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import chalk from 'chalk'
import { ServerEventBus } from '@tanstack/devtools-event-bus/server'
import { handleDevToolsViteRequest } from './utils'
import { DEFAULT_EDITOR_CONFIG, handleOpenSource } from './editor'
import { addSourceToJsx } from './inject-source'
import type { EditorConfig } from './editor'
import type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server'
import type { Plugin } from 'vite'
Expand Down Expand Up @@ -40,6 +41,24 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
const bus = new ServerEventBus(args?.eventBusConfig)

return [
{
enforce: 'pre',
name: '@tanstack/devtools:inject-source',
apply(config) {
return config.mode === 'development'
},
transform(code, id) {
if (
id.includes('node_modules') ||
id.includes('?raw') ||
id.includes('dist') ||
id.includes('build')
)
return code

return addSourceToJsx(code, id)
},
},
{
enforce: 'pre',
name: '@tanstack/devtools:custom-server',
Expand Down Expand Up @@ -87,6 +106,12 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
}),
)
},
transform(code) {
if (code.includes('__TSD_PORT__')) {
code = code.replace('__TSD_PORT__', String(port))
}
return code
},
},
{
name: '@tanstack/devtools:better-console-logs',
Expand Down
28 changes: 27 additions & 1 deletion packages/devtools/src/devtools.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Show, createEffect, createSignal } from 'solid-js'
import { Show, createEffect, createSignal, onCleanup } from 'solid-js'
import { createShortcut } from '@solid-primitives/keyboard'
import {
useDevtoolsSettings,
Expand Down Expand Up @@ -151,6 +151,32 @@ export default function DevTools() {
}
})

createEffect(() => {
// this will only work with the Vite plugin
const openSourceHandler = (e: Event) => {
const isShiftHeld = (e as KeyboardEvent).shiftKey
const isCtrlHeld =
(e as KeyboardEvent).ctrlKey || (e as KeyboardEvent).metaKey
if (!isShiftHeld || !isCtrlHeld) return

if (e.target instanceof HTMLElement) {
const dataSource = e.target.getAttribute('data-tsd-source')
window.getSelection()?.removeAllRanges()
if (dataSource) {
e.preventDefault()
e.stopPropagation()
fetch(
`http://localhost:__TSD_PORT__/__tsd/open-source?source=${dataSource}`,
).catch(() => {})
}
}
}
window.addEventListener('click', openSourceHandler)
onCleanup(() => {
window.removeEventListener('click', openSourceHandler)
})
})

return (
<div ref={setRootEl} data-testid={TANSTACK_DEVTOOLS}>
<Show
Expand Down
Loading