devtools-vite console pipe: infinite feedback loop with Vite 8 `server.forwardConsole` — one console entry floods browser + terminal
Nessuno ha ancora preso questa issue.
- Lingua principale
- TypeScript
- Stelle
- 499
- Fork
- 100
- Merge medio
- 1g 17h
- PR unite (30g)
- 4
Descrizione
Which project does this relate to?
Devtools
Describe the bug
@tanstack/devtools-vite's console pipe enters an infinite feedback loop with Vite 8's server.forwardConsole (on by default): a single console.error/console.warn anywhere — client or server — floods both the browser console and the terminal with thousands of nested lines per minute, indefinitely:
9:27:59 PM [vite] (client) [console.error] [Server] 9:27:59 PM [vite] (client) [console.error] [Server] 9:27:59 PM [vite] (client) [console.error] [Se…
The cycle:
- Any console entry in the browser → Vite 8
forwardConsolere-prints it in the terminal via the server logger (… [vite] (client) [console.error] …). - The console-pipe's server-side console patch intercepts that print. Its recursion guard only skips messages containing
[TSD Console Pipe]/[@tanstack/devtools, so a Vite-forwarded client log is treated as a server log and broadcast to the browser over SSE. - The browser mirror prints it (
%c[Server]%c …) → Vite forwards it again → goto 1. Each hop nests the previous message inside itself.
In a real TanStack Start app (Vite 8.0.16, devtools-vite 0.8.1) we measured one failed fetch turning into 37,779 browser console entries in 30s and a 2.5 GB terminal log in about a minute.
The related fix in 0.6.1 ("console pipe feedback loop … with Vite 8") does not cover this path — 0.7.0 and 0.8.1 both reproduce.
Your Example Website or App
See minimal reproduction below (4 files)
Steps to Reproduce the Bug or Issue
package.json
{
"name": "tsd-console-loop-repro",
"private": true,
"type": "module",
"scripts": { "dev": "vite" },
"devDependencies": {
"@tanstack/devtools-vite": "0.8.1",
"vite": "8.0.16"
}
}
vite.config.js — bare Vite + devtools + a 10-line SSR middleware (the pipe's server console patch is only injected into SSR modules, so a plain SPA doesn't show it):
import { devtools } from '@tanstack/devtools-vite'
export default {
appType: 'custom',
plugins: [
devtools(),
{
name: 'mini-ssr',
configureServer(server) {
return () => {
server.middlewares.use(async (req, res) => {
const { render } = await server.ssrLoadModule('/entry-server.js')
res.setHeader('content-type', 'text/html')
res.end(await server.transformIndexHtml(req.url ?? '/', render()))
})
}
},
},
],
}
entry-server.js — the <html marker makes the console-pipe transform patch the server console here:
export function render() {
return '<html><body><h1>tsd console loop repro</h1><script type="module" src="/main.js"></script></body></html>'
}
main.js — the createRoot marker mimics a real client entry (which is what the client-side pipe injection keys on):
function createRoot(el) {
el.textContent = 'mounted'
}
createRoot(document.querySelector('h1'))
// A single console entry seeds the infinite echo.
console.error('seed')
Then:
pnpm install && pnpm dev- Open the page in a browser.
- Watch the terminal and the browser console.
Measured on this repro (Playwright counting console messages, no interaction after load):
| 10s | 20s | 30s | |
|---|---|---|---|
| browser console entries | 189 | 374 | 559 |
…growing without bound; the dev-server terminal shows the same nested [vite] (client) [console.error] [Server] lines.
Expected behavior
One console.error('seed') produces one line in the browser and (via Vite's forwarding) one line in the terminal. Vite-forwarded client logs should not be re-broadcast to the browser as server logs.
Screenshots or Videos
No response
Platform
- OS: macOS 15 (Darwin 25.4.0)
- Node: 22.20.0
- vite: 8.0.16 (
server.forwardConsoledefault-enabled) - @tanstack/devtools-vite: 0.8.1 (also reproduces on 0.7.0)
Additional context
We're currently carrying this as a pnpm patch — extending the recursion guard in the generated console-pipe code so the server-side patch skips Vite-forwarded client logs:
// Skip our own TSD Console Pipe logs to avoid recursion/noise
if (args.length > 0 && typeof args[0] === 'string' &&
(args[0].indexOf('[TSD Console Pipe]') !== -1 ||
args[0].indexOf('[@tanstack/devtools') !== -1)) {
return;
}
+
+ // Vite 8's server.forwardConsole re-prints CLIENT console output in
+ // the terminal ("[vite] (client) [console.warn] ..."). Those are not
+ // server logs — re-broadcasting them to the browser makes the browser
+ // log them again, which vite forwards again: an infinite
+ // client->server->client echo. Skip vite-forwarded client logs.
+ if (isServer && args.length > 0 && typeof args[0] === 'string' &&
+ (args[0].indexOf('(client)') !== -1 ||
+ args[0].indexOf('[console.') !== -1)) {
+ return;
+ }
With that guard in place: same app, same seed error — browser console stays at 5 entries (flat), terminal stays quiet, and genuine server logs still mirror into the browser once, as intended. A marker-based handshake between the pipe and Vite's forwarder would probably be more robust than string matching, but the diff above demonstrates the loop and the fix.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia con la riproduzione nei quattro file: vite.config.js, entry-server.js, main.js e package.json, quindi segui l’iniezione di console-pipe lato server usata dall’entry SSR. Riproduci il problema con Vite 8 e osserva sia l’output del browser sia quello del terminale. Il lavoro è completato quando un errore di console preimpostato rimane circoscritto, i log client inoltrati da Vite non vengono ritrasmessi e i log server autentici continuano a essere rispecchiati una sola volta.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript, vite
- Ambito
- build-system, devtools
- Tipo di issue
- Bug
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 72/100