Che cosa sono le mappe di origine?

Le mappe sorgente sono uno strumento fondamentale nello sviluppo web moderno che semplifica notevolmente il debugging. Questa pagina illustra le nozioni di base delle mappe di origine, come vengono generate e come migliorano l'esperienza di debug.

La necessità di mappe di origine

Le prime app web erano costruite con una bassa complessità. Gli sviluppatori hanno implementato file HTML, CSS e JavaScript direttamente sul web.

Le app web più moderne e complesse possono richiedere una serie di strumenti nel loro flussi di lavoro di sviluppo. Ad esempio:

Una breve panoramica dei vari strumenti.
Alcuni degli strumenti di sviluppo di app web comuni.

Questi strumenti richiedono una procedura di compilazione per transpilare il codice in HTML, JavaScript e CSS standard che i browser possono comprendere. È anche prassi comune ottimizzare il rendimento riducendo al minimo e combinando questi file utilizzando uno strumento come Terser.

Ad esempio, utilizzando gli strumenti di compilazione, possiamo transpilare e comprimere il seguente file TypeScript in una singola riga di JavaScript. Puoi provarlo personalmente in questa demo su GitHub.

/* A TypeScript demo: example.ts */

document.querySelector('button')?.addEventListener('click', () => {
  const num: number = Math.floor(Math.random() * 101);
  const greet: string = 'Hello';
  (document.querySelector('p') as HTMLParagraphElement).innerText = `${greet}, you are no. ${num}!`;
  console.log(num);
});

Una versione compressa sarebbe:

/* A compressed JavaScript version of the TypeScript demo: example.min.js  */

document.querySelector("button")?.addEventListener("click",(()=>{const e=Math.floor(101*Math.random());document.querySelector("p").innerText=`Hello, you are no. ${e}!`,console.log(e)}));

Tuttavia, la compressione del codice può rendere più difficile il debug. Le mappe di origine possono risolvere questo problema: mappando il codice compilato al codice originale, possono aiutarti a trovare rapidamente l'origine di un errore.

Genera mappe di origine

Le mappe sorgente sono file i cui nomi terminano con .map (ad esempio example.min.js.map e styles.css.map). Possono essere generate dalla maggior parte degli strumenti di compilazione, tra cui Vite, webpack, Rollup, Parcel e esbuild.

Alcuni strumenti includono le mappe di origine per impostazione predefinita. Per altri potrebbe essere necessaria una configurazione aggiuntiva per produrli:

/* Example configuration: vite.config.js */
/* https://vitejs.dev/config/ */

export default defineConfig({
  build: {
    sourcemap: true, // enable production source maps
  },
  css: {
    devSourcemap: true // enable CSS source maps during development
  }
})

Informazioni sulla mappa di origine

Per facilitare il debug, questi file mappa di origine contengono informazioni essenziali su come il codice compilato viene mappato al codice originale. Ecco un esempio di mappa di origine:

{
  "mappings": "AAAAA,SAASC,cAAc,WAAWC, ...",
  "sources": ["src/script.ts"],
  "sourcesContent": ["document.querySelector('button')..."],
  "names": ["document","querySelector", ...],
  "version": 3,
  "file": "example.min.js.map"
}

Per comprendere ciascuno di questi campi, puoi leggere la specifica della mappa delle origini o l'articolo L'anatomia di una mappa delle origini.

La parte più importante di una mappa di origine è il campo mappings. Utilizza una stringa codificata VLQ in base 64 per mappare le righe e le posizioni nel file compilato al corrispondente file originale. Puoi visualizzare questa mappatura utilizzando un visualizzatore di mappe di origine come source-map-visualization o Visualizzazione mappa di origine.

Una visualizzazione della mappa di origine.
Una visualizzazione dell'esempio di codice precedente, generata da un visualizzatore.

La colonna generata a sinistra mostra i contenuti compressi, mentre la colonna originale mostra la fonte originale.

Il visualizzatore assegna un colore a ogni riga della colonna originale con il codice corrispondente nella colonna generata.

La sezione mappings mostra le mappature decodificate del codice. Ad esempio, la voce 65 -> 2:2 indica:

  • Codice generato: la parola const inizia nella posizione 65 dei contenuti compressi.
  • Codice originale: la parola const inizia nella riga 2 e nella colonna 2 dei contenuti originali.
Voce di mappatura.
La visualizzazione della mappatura, incentrata sulla voce 65 -> 2:2.

In questo modo, gli sviluppatori possono identificare rapidamente la relazione tra il codice minimizzato e il codice originale, rendendo il debug un processo più semplice.

Gli strumenti per sviluppatori del browser applicano queste mappe sorgente per aiutarti a individuare rapidamente i problemi di debug nel browser.

Strumenti per sviluppatori che applicano una mappa di origine.
Un esempio di come gli strumenti per sviluppatori del browser applicano le mappe sorgente e mostrano le mappature tra i file.

Estensioni mappa di origine

Le mappe di origine supportano i campi di estensioni personalizzate che iniziano con un prefisso x_. Un esempio è il campo di estensione x_google_ignoreList proposto da DevTools di Chrome. Consulta x_google_ignoreList per scoprire di più su come queste estensioni ti aiutano a concentrarti sul codice.

Svantaggi delle mappe di origine

Purtroppo, le mappature delle origini non sono sempre complete come ti serve. Nel nostro primo esempio, la variabile greet è stata ottimizzata durante il processo di compilazione, anche se il suo valore è incorporato direttamente nell'output della stringa finale.

La variabile greet non è mappata.
La variabile greet nel codice originale non è presente nella mappatura.

In questo caso, quando esegui il debug del codice, gli strumenti per sviluppatori potrebbero non essere in grado di inferire e visualizzare il valore effettivo. Questo tipo di errore può complicare il monitoraggio e l'analisi del codice.

La variabile greet non è definita.
Lo strumento per sviluppatori non riesce a trovare un valore per greet.

Si tratta di un problema che deve essere risolto nel design delle mappe di origine. Una potenziale soluzione è includere le informazioni sull'ambito nelle mappe di origine come fanno gli altri linguaggi di programmazione con le informazioni di debug.

Tuttavia, questo richiede che l'intero ecosistema collabori per migliorare la specifica e l'implementazione della mappa di origine. Per seguire l'evoluzione del miglioramento della possibilità di eseguire il debug con le mappe di origine, consulta la proposta per la versione 4 delle mappe di origine su GitHub.