Skip to content

Bun parla il WebKit Inspector Protocol, quindi puoi eseguire il debug del tuo codice con un debugger interattivo. A scopo dimostrativo, considera il seguente semplice server web.

Debug di JavaScript e TypeScript

typescript
Bun.serve({
  fetch(req) {
    console.log(req.url);
    return new Response("Hello, world!");
  },
});

--inspect

Per abilitare il debug durante l'esecuzione del codice con Bun, usa il flag --inspect. Questo avvia automaticamente un server WebSocket su una porta disponibile che può essere usata per ispezionare il processo Bun in esecuzione.

sh
bun --inspect server.ts
txt
------------------ Bun Inspector ------------------
In ascolto su:
  ws://localhost:6499/0tqxs9exrgrm

Ispeziona nel browser:
  https://debug.bun.sh/#localhost:6499/0tqxs9exrgrm
------------------ Bun Inspector ------------------

--inspect-brk

Il flag --inspect-brk si comporta in modo identico a --inspect, tranne per il fatto che inietta automaticamente un breakpoint alla prima riga dello script eseguito. Questo è utile per il debug di script che vengono eseguiti rapidamente ed escono immediatamente.

--inspect-wait

Il flag --inspect-wait si comporta in modo identico a --inspect, tranne per il fatto che il codice non verrà eseguito finché un debugger non si sarà collegato al processo in esecuzione.

Impostare una porta o un URL per il debugger

Indipendentemente dal flag che usi, puoi opzionalmente specificare un numero di porta, un prefisso URL o entrambi.

sh
bun --inspect=4000 server.ts
bun --inspect=localhost:4000 server.ts
bun --inspect=localhost:4000/prefix server.ts

Debugger

Vari strumenti di debug possono connettersi a questo server per fornire un'esperienza di debug interattiva.

debug.bun.sh

Bun ospita un debugger basato sul web su debug.bun.sh. È una versione modificata di Web Inspector Interface di WebKit, che risulterà familiare agli utenti di Safari.

Apri l'URL debug.bun.sh fornito nel tuo browser per avviare una sessione di debug. Da questa interfaccia, potrai visualizzare il codice sorgente del file in esecuzione, visualizzare e impostare breakpoint ed eseguire codice con la console integrata.

Impostiamo un breakpoint. Naviga alla scheda Sources; dovresti vedere il codice visto prima. Clicca sul numero di riga 3 per impostare un breakpoint sulla nostra istruzione console.log(req.url).

Poi visita http://localhost:3000 nel tuo browser web. Questo invierà una richiesta HTTP al nostro server web localhost. Sembrerà che la pagina non si stia caricando. Perché? Perché il programma ha messo in pausa l'esecuzione al breakpoint che abbiamo impostato in precedenza.

Nota come è cambiata l'interfaccia utente.

A questo punto c'è molto che possiamo fare per ispezionare l'ambiente di esecuzione corrente. Possiamo usare la console in basso per eseguire codice arbitrario nel contesto del programma, con pieno accesso alle variabili in scope al nostro breakpoint.

Sul lato destro del riquadro Sources, possiamo vedere tutte le variabili locali attualmente in scope ed espandere per vedere le loro proprietà e metodi. Qui, stiamo ispezionando la variabile req.

Nella parte in alto a sinistra del riquadro Sources, possiamo controllare l'esecuzione del programma.

Ecco un cheat sheet che spiega le funzioni dei pulsanti di controllo del flusso.

  • Continua l'esecuzione dello script — continua l'esecuzione del programma fino al prossimo breakpoint o eccezione.
  • Step over — Il programma continuerà alla riga successiva.
  • Step into — Se l'istruzione corrente contiene una chiamata di funzione, il debugger "entrerà" nella funzione chiamata.
  • Step out — Se l'istruzione corrente è una chiamata di funzione, il debugger finirà di eseguire la chiamata, poi "uscirà" dalla funzione alla posizione da cui è stata chiamata.

Debugger di Visual Studio Code

Il supporto sperimentale per il debug di script Bun è disponibile in Visual Studio Code. Per usarlo, dovrai installare l'estensione Bun VSCode.


Debug delle Richieste di Rete

La variabile d'ambiente BUN_CONFIG_VERBOSE_FETCH ti permette di registrare automaticamente le richieste di rete effettuate con fetch() o node:http.

ValoreDescrizione
curlStampa le richieste come comandi curl.
trueStampa le informazioni di request e response
falseNon stampa nulla. Default

Stampare le richieste fetch e node:http come comandi curl

Bun supporta anche la stampa delle richieste di rete fetch() e node:http come comandi curl impostando la variabile d'ambiente BUN_CONFIG_VERBOSE_FETCH su curl. Questo stampa la richiesta fetch come un comando curl su singola riga per permetterti di copiare e incollare nel tuo terminale per replicare la richiesta.

ts
process.env.BUN_CONFIG_VERBOSE_FETCH = "curl";

await fetch("https://example.com", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ foo: "bar" }),
});
txt
[fetch] $ curl --http1.1 "https://example.com/" -X POST -H "content-type: application/json" -H "Connection: keep-alive" -H "User-Agent: Bun/1.3.3" -H "Accept: */*" -H "Host: example.com" -H "Accept-Encoding: gzip, deflate, br" --compressed -H "Content-Length: 13" --data-raw "{\"foo\":\"bar\"}"
[fetch] > HTTP/1.1 POST https://example.com/
[fetch] > content-type: application/json
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br
[fetch] > Content-Length: 13

[fetch] < 200 OK
[fetch] < Accept-Ranges: bytes
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Tue, 18 Jun 2024 05:12:07 GMT
[fetch] < Etag: "3147526947"
[fetch] < Expires: Tue, 25 Jun 2024 05:12:07 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: EOS (vny/044F)
[fetch] < Content-Length: 1256

Le righe con [fetch] > sono la richiesta dal tuo codice locale, e le righe con [fetch] < sono la response dal server remoto.

La variabile d'ambiente BUN_CONFIG_VERBOSE_FETCH è supportata sia nelle richieste fetch() che node:http, quindi dovrebbe funzionare senza problemi.

Per stampare senza il comando curl, imposta BUN_CONFIG_VERBOSE_FETCH su true.

ts
process.env.BUN_CONFIG_VERBOSE_FETCH = "true";

await fetch("https://example.com", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ foo: "bar" }),
});
txt
[fetch] > HTTP/1.1 POST https://example.com/
[fetch] > content-type: application/json
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br
[fetch] > Content-Length: 13

[fetch] < 200 OK
[fetch] < Accept-Ranges: bytes
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Tue, 18 Jun 2024 05:12:07 GMT
[fetch] < Etag: "3147526947"
[fetch] < Expires: Tue, 25 Jun 2024 05:12:07 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: EOS (vny/044F)
[fetch] < Content-Length: 1256

Stacktrace e sourcemap

Bun transpila ogni file, il che potrebbe far pensare che gli stack trace che vedi nella console punterebbero inutilmente all'output transpilato. Per risolvere questo problema, Bun genera e serve automaticamente file con sourcemap per ogni file che transpila. Quando vedi uno stack trace nella console, puoi cliccare sul percorso del file e essere portato al codice sorgente originale, anche se era scritto in TypeScript o JSX, o ha qualche altra trasformazione applicata.

Bun carica automaticamente le sourcemap sia a runtime quando transpila i file on-demand, sia quando usa bun build per precompilare i file in anticipo.

Anteprima del codice sorgente con evidenziazione della sintassi

Per aiutare con il debug, Bun stampa automaticamente una piccola anteprima del codice sorgente quando si verifica un'eccezione o un rifiuto non gestito. Puoi simulare questo comportamento chiamando Bun.inspect(error):

ts
// Crea un errore
const err = new Error("Qualcosa è andato storto");
console.log(Bun.inspect(err, { colors: true }));

Questo stampa un'anteprima con evidenziazione della sintassi del codice sorgente dove si è verificato l'errore, insieme al messaggio di errore e allo stack trace.

ts
1 | // Crea un errore
2 | const err = new Error("Qualcosa è andato storto");
                ^
error: Qualcosa è andato storto
      at file.js:2:13

Stack Trace V8

Bun usa JavaScriptCore come motore, ma gran parte dell'ecosistema Node.js e npm si aspetta V8. I motori JavaScript differiscono nella formattazione di error.stack. Bun intende essere un rimpiazzo drop-in per Node.js, e questo significa che è nostro compito assicurarci che anche se il motore è diverso, gli stack trace siano il più simili possibile.

Ecco perché quando registri error.stack in Bun, la formattazione di error.stack è la stessa del motore V8 di Node.js. Questo è particolarmente utile quando usi librerie che si aspettano stack trace V8.

API Stack Trace V8

Bun implementa la V8 Stack Trace API, che è un insieme di funzioni che ti permettono di manipolare gli stack trace.

Error.prepareStackTrace

La funzione Error.prepareStackTrace è una funzione globale che ti permette di personalizzare l'output dello stack trace. Questa funzione viene chiamata con l'oggetto errore e un array di oggetti CallSite e ti permette di restituire uno stack trace personalizzato.

ts
Error.prepareStackTrace = (err, stack) => {
  return stack.map(callSite => {
    return callSite.getFileName();
  });
};

const err = new Error("Qualcosa è andato storto");
console.log(err.stack);
// [ "error.js" ]

L'oggetto CallSite ha i seguenti metodi:

MethodRestituisce
getThisValore this della chiamata di funzione
getTypeNametypeof this
getFunctionoggetto function
getFunctionNamenome della funzione come stringa
getMethodNamenome del metodo come stringa
getFileNamenome del file o URL
getLineNumbernumero di riga
getColumnNumbernumero di colonna
getEvalOriginundefined
getScriptNameOrSourceURLURL sorgente
isToplevelrestituisce true se la funzione è nello scope globale
isEvalrestituisce true se la funzione è una chiamata eval
isNativerestituisce true se la funzione è nativa
isConstructorrestituisce true se la funzione è un costruttore
isAsyncrestituisce true se la funzione è async
isPromiseAllNon ancora implementato.
getPromiseIndexNon ancora implementato.
toStringrestituisce una rappresentazione stringa del call site

In alcuni casi, l'oggetto Function potrebbe essere già stato garbage collected, quindi alcuni di questi metodi potrebbero restituire undefined.

Error.captureStackTrace(error, startFn)

La funzione Error.captureStackTrace ti permette di catturare uno stack trace in un punto specifico del tuo codice, piuttosto che nel punto in cui è stato lanciato l'errore.

Questo può essere utile quando hai callback o codice asincrono che rende difficile determinare da dove ha origine un errore. Il 2° argomento di Error.captureStackTrace è la funzione da cui vuoi che inizi lo stack trace.

Ad esempio, il codice sottostante farà sì che err.stack punti al codice che chiama fn(), anche se l'errore è stato lanciato in myInner.

ts
const fn = () => {
  function myInner() {
    throw err;
  }

  try {
    myInner();
  } catch (err) {
    console.log(err.stack);
    console.log("");
    console.log("-- captureStackTrace --");
    console.log("");
    Error.captureStackTrace(err, fn);
    console.log(err.stack);
  }
};

fn();
txt
Error: here!
    at myInner (file.js:4:15)
    at fn (file.js:8:5)
    at module code (file.js:17:1)
    at moduleEvaluation (native)
    at moduleEvaluation (native)
    at <anonymous> (native)

-- captureStackTrace --

Error: here!
    at module code (file.js:17:1)
    at moduleEvaluation (native)
    at moduleEvaluation (native)
    at <anonymous> (native)

Bun a cura di www.bunjs.com.cn