Pengantar Peta Sumber JavaScript

Ryan Seddon

Pernahkah Anda berharap dapat membuat kode sisi klien tetap dapat dibaca dan yang lebih penting dapat di-debug bahkan setelah Anda menggabungkan dan meminifikasinya, tanpa memengaruhi performa? Kini Anda dapat melakukannya dengan memanfaatkan keajaiban peta sumber.

Source maps adalah cara untuk memetakan kembali file gabungan/yang diminifikasi ke status tidak dibangun. Saat membangun untuk produksi, bersamaan dengan meminifikasi dan menggabungkan file JavaScript, Anda akan membuat peta sumber yang menyimpan informasi tentang file asli. Saat melakukan kueri nomor baris dan kolom tertentu di JavaScript yang dihasilkan, Anda bisa melakukan pencarian di peta sumber yang menampilkan lokasi asli. Alat pengembang (saat ini dibuat oleh WebKit setiap malam, Google Chrome, atau Firefox 23+) dapat mengurai peta sumber secara otomatis dan membuatnya seolah-olah Anda sedang menjalankan file yang tidak diperkecil dan tidak digabungkan.

Demo ini memungkinkan Anda mengklik kanan di mana saja dalam textarea yang berisi sumber yang dihasilkan. Pilih "Dapatkan lokasi asli" akan mengajukan kueri peta sumber dengan meneruskan nomor baris dan kolom yang dihasilkan, dan mengembalikan posisi dalam kode asli. Pastikan konsol Anda terbuka sehingga Anda dapat melihat output-nya.

Contoh penggunaan library peta sumber Mozilla JavaScript.

Dunia nyata

Sebelum melihat implementasi nyata Source Maps, pastikan Anda telah mengaktifkan fitur peta sumber di Chrome Canary atau WebKit setiap malam dengan mengeklik roda gigi setelan di panel alat pengembangan dan mencentang opsi "Aktifkan peta sumber".

Cara mengaktifkan source maps di alat pengembangan WebKit.

Firefox 23+ memiliki source maps yang diaktifkan secara bawaan pada alat pengembangan bawaan.

Cara mengaktifkan source maps di alat developer Firefox.

Mengapa saya harus memperhatikan peta sumber?

Saat ini pemetaan sumber hanya berfungsi antara JavaScript yang tidak dikompresi/digabungkan ke JavaScript yang dikompresi/tidak digabungkan, namun ke depannya akan tampak cerah dengan pembahasan bahasa yang dikompilasi ke JavaScript seperti CoffeeScript, dan bahkan kemungkinan menambahkan dukungan untuk praprosesor CSS seperti SASS atau LESS.

Di masa mendatang, kami dapat dengan mudah menggunakan hampir semua bahasa seolah-olah bahasa tersebut didukung di browser dengan peta sumber:

  • CoffeeScript
  • ECMAScript 6 dan yang lebih baru
  • SASS/LESS dan lainnya
  • Hampir semua bahasa yang dikompilasi ke JavaScript

Lihat screencast CoffeeScript yang di-debug dalam build eksperimental konsol Firefox:

Google Web Toolkit (GWT) baru-baru ini menambahkan dukungan untuk Source Maps. Ray Cromwell dari tim GWT melakukan screencast yang luar biasa, yang menunjukkan cara kerja dukungan peta sumber.

Contoh lain yang saya kumpulkan menggunakan library Traceur Google yang memungkinkan Anda menulis ES6 (ECMAScript 6 atau Next) dan mengompilasinya ke kode yang kompatibel dengan ES3. Compiler Traceur juga menghasilkan peta sumber. Lihat demo fitur dan class ES6 yang digunakan seolah-olah didukung secara native di browser, berkat peta sumber.

Textarea dalam demo ini juga memungkinkan Anda untuk menulis ES6 yang akan dikompilasi dengan cepat dan menghasilkan peta sumber ditambah kode ES3 yang setara.

Proses debug Traceur ES6 menggunakan peta sumber.

Demo: Menulis ES6, men-debug, melihat cara kerja pemetaan sumber

Bagaimana cara kerja peta sumber?

Satu-satunya compiler/minifier JavaScript yang saat ini memiliki dukungan untuk pembuatan peta sumber adalah compiler Closure. (Saya akan menjelaskan cara menggunakannya nanti.) Setelah Anda menggabungkan dan meminifikasi JavaScript, di samping itu akan ada file peta sumber.

Saat ini, compiler Closure tidak menambahkan komentar khusus di bagian akhir yang diperlukan untuk menunjukkan ke alat developer browser bahwa peta sumber tersedia:

//# sourceMappingURL=/path/to/file.js.map

Hal ini memungkinkan alat developer memetakan kembali panggilan ke lokasinya dalam file sumber asli. Sebelumnya, pragma komentar adalah //@ tetapi karena beberapa masalah dengan komentar tersebut dan komentar kompilasi bersyarat IE, keputusan dibuat untuk mengubahnya menjadi //#. Saat ini Chrome Canary, WebKit Nightly, dan Firefox 24+ mendukung pragma komentar baru. Perubahan sintaksis ini juga memengaruhi sourceURL.

Jika tidak menyukai komentar yang aneh, Anda dapat menyetel header khusus pada file JavaScript yang telah dikompilasi:

X-SourceMap: /path/to/file.js.map

Sukai komentar, ini akan memberi tahu konsumen peta sumber Anda di mana harus mencari peta sumber yang terkait dengan file JavaScript. Header ini juga mengatasi masalah referensi peta sumber dalam bahasa yang tidak mendukung komentar satu baris.

Contoh webKit Devtools aktif dan peta sumber nonaktif.

File peta sumber hanya akan didownload jika Anda mengaktifkan peta sumber dan alat developer terbuka. Anda juga harus mengupload file asli sehingga alat developer dapat mereferensikan dan menampilkannya saat diperlukan.

Bagaimana cara membuat peta sumber?

Anda harus menggunakan Compiler Penutupan untuk meminifikasi, menyambungkan, dan membuat peta sumber untuk file JavaScript Anda. Perintahnya adalah sebagai berikut:

java -jar compiler.jar \
--js script.js \
--create_source_map ./script-min.js.map \
--source_map_format=V3 \
--js_output_file script-min.js

Dua flag perintah yang penting adalah --create_source_map dan --source_map_format. Ini diperlukan karena versi default adalah V2 dan kami hanya ingin bekerja dengan V3.

Anatomi peta sumber

Untuk lebih memahami peta sumber, kita akan mengambil contoh kecil file peta sumber yang akan dihasilkan oleh compiler Closure dan mempelajari lebih detail tentang cara kerja bagian "pemetaan". Contoh berikut adalah sedikit variasi dari contoh spesifikasi V3.

{
    version : 3,
    file: "out.js",
    sourceRoot : "",
    sources: ["foo.js", "bar.js"],
    names: ["src", "maps", "are", "fun"],
    mappings: "AAgBC,SAAQ,CAAEA"
}

Di atas, Anda dapat melihat bahwa peta sumber adalah literal objek yang berisi banyak info menarik:

  • Nomor versi yang menjadi dasar peta sumber
  • Nama file dari kode yang dibuat (File produksi minifed/gabungan Anda)
  • sourceRoot memungkinkan Anda menambahkan sumber dengan struktur folder - ini juga merupakan teknik menghemat ruang
  • sumber berisi semua nama file yang digabungkan
  • nama berisi semua nama variabel/metode yang muncul di seluruh kode Anda.
  • Terakhir, properti pemetaan adalah tempat keajaiban terjadi menggunakan nilai Base64 VLQ. Penghematan ruang yang sesungguhnya dilakukan di sini.

Base64 VLQ dan menjaga agar peta sumber tetap kecil

Awalnya, spesifikasi peta sumber memiliki output yang sangat panjang dari semua pemetaan dan menghasilkan ukuran peta sumber sekitar 10 kali ukuran kode yang dihasilkan. Versi dua menguranginya sekitar 50% dan versi tiga menguranginya lagi sebesar 50%, jadi untuk file 133kB Anda berakhir dengan peta sumber ~ 300kB.

Jadi bagaimana mereka mengurangi ukuran sambil tetap mempertahankan pemetaan yang kompleks?

VLQ (Jumlah Panjang Variabel) digunakan bersama dengan mengenkode nilai ke nilai Base64. Properti pemetaan adalah string yang sangat besar. Dalam string ini terdapat titik koma (;) yang mewakili nomor baris dalam file yang dihasilkan. Dalam setiap baris terdapat koma (,) yang mewakili setiap segmen dalam baris tersebut. Masing-masing segmen ini adalah 1, 4 atau 5 dalam bidang dengan panjang variabel. Beberapa mungkin tampak lebih panjang tetapi ini berisi bit lanjutan. Setiap segmen dibuat berdasarkan segmen sebelumnya, yang membantu mengurangi ukuran file karena setiap bit relatif terhadap segmen sebelumnya.

Pengelompokan segmen dalam file JSON peta sumber.

Seperti yang disebutkan di atas, setiap segmen dapat memiliki panjang variabel 1, 4 atau 5. Diagram ini dianggap memiliki panjang variabel empat dengan satu bit lanjutan (g). Kami akan menguraikan segmen ini dan menunjukkan bagaimana peta sumber membuat lokasi asli.

Nilai yang ditampilkan di atas hanyalah nilai yang didekode Base64, ada beberapa pemrosesan lagi untuk mendapatkan nilai sebenarnya. Setiap segmen biasanya mencakup lima hal:

  • Kolom yang dihasilkan
  • File asli tempat ini muncul
  • Nomor baris asli
  • Kolom asli
  • Dan, jika ada, nama asli

Tidak setiap segmen memiliki nama, nama metode, atau argumen, sehingga keseluruhan segmen akan beralih antara empat dan lima panjang variabel. Nilai g pada diagram segmen di atas disebut bit lanjutan, yang memungkinkan pengoptimalan lebih lanjut pada tahap decoding Base64 VLQ. Bit lanjutan memungkinkan Anda membangun nilai segmen sehingga Anda dapat menyimpan angka besar tanpa harus menyimpan angka besar, teknik penghematan ruang yang sangat pintar yang berakar pada format midi.

Setelah diproses lebih lanjut, diagram AAgBC di atas akan menampilkan 0, 0, 32, 16, 1 - 32 menjadi bit kelanjutan yang membantu membangun nilai 16 berikut. B yang sepenuhnya didekode dalam Base64 adalah 1. Jadi nilai penting yang digunakan adalah 0, 0, 16, 1. Ini kemudian memungkinkan kita mengetahui bahwa baris 1 (baris disimpan dihitung oleh titik koma) kolom 0 dari peta file yang dihasilkan ke file 0 (array file 0 adalah foo.js), baris 16 di kolom 1.

Untuk menunjukkan cara segmen didekode, saya akan merujuk ke library JavaScript Source Map Mozilla. Anda juga dapat melihat kode pemetaan sumber alat dev WebKit yang juga ditulis dalam JavaScript.

Untuk memahami dengan baik cara mendapatkan nilai 16 dari B, kita perlu memiliki pemahaman dasar tentang operator bitwise dan cara kerja spesifikasi untuk pemetaan sumber. Digit sebelumnya, g, ditandai sebagai bit kelanjutan dengan membandingkan digit (32) dan VLQ_CONTINUATION_BIT (biner 100000 atau 32) menggunakan operator AND (&) bitwise.

32 & 32 = 32
// or
100000
|
|
V
100000

Ini mengembalikan 1 di setiap posisi bit di mana keduanya muncul. Jadi, nilai 33 & 32 yang didekode Base64 akan menampilkan 32 karena hanya membagikan lokasi 32 bit seperti yang dapat Anda lihat pada diagram di atas. Hal ini kemudian meningkatkan nilai pergeseran bit sebesar 5 untuk setiap bit lanjutan sebelumnya. Dalam kasus di atas hanya digeser 5 sekali, jadi bergeser ke kiri 1 (B) sebesar 5.

1 <<../ 5 // 32

// Shift the bit by 5 spots
______
|    |
V    V
100001 = 100000 = 32

Nilai tersebut kemudian dikonversi dari nilai yang ditandatangani VLQ dengan menggeser ke kanan angka (32) satu tempat.

32 >> 1 // 16
//or
100000
|
 |
 V
010000 = 16

Seperti itulah cara mengubah 1 menjadi 16. Proses ini mungkin tampak terlalu rumit, tetapi setelah angkanya mulai bertambah besar, hal ini menjadi lebih masuk akal.

Potensi masalah XSSI

Spesifikasi ini menyebutkan masalah penyertaan skrip lintas situs yang dapat muncul dari penggunaan peta sumber. Untuk mengurangi hal ini, sebaiknya awali baris pertama peta sumber Anda dengan ")]}" untuk sengaja membatalkan JavaScript sehingga error sintaks akan ditampilkan. Alat developer WebKit sudah dapat menangani hal ini.

if (response.slice(0, 3) === ")]}") {
    response = response.substring(response.indexOf('\n'));
}

Seperti yang ditunjukkan di atas, tiga karakter pertama dipotong untuk memeriksa apakah karakter tersebut cocok dengan kesalahan sintaks dalam spesifikasi dan jika demikian akan menghapus semua karakter yang mengarah ke entitas baris baru pertama (\n).

Cara kerja sourceURL dan displayName: Fungsi evaluasi dan anonim

Meskipun bukan bagian dari spesifikasi peta sumber, dua konvensi berikut memungkinkan Anda membuat pengembangan lebih mudah saat bekerja dengan fungsi anonim dan evaluasi.

Helper pertama terlihat sangat mirip dengan properti //# sourceMappingURL dan sebenarnya disebutkan dalam spesifikasi peta sumber V3. Dengan menyertakan komentar khusus berikut dalam kode Anda, yang akan dievaluasi, Anda dapat menamai evaluasi agar muncul sebagai nama yang lebih logis di alat developer Anda. Lihat demo sederhana menggunakan compiler CoffeeScript:

Demo: Lihat kode eval() ditampilkan sebagai skrip melalui URL sumber

//# sourceURL=sqrt.coffee
Tampilan komentar khusus sourceURL di alat developer

Helper lainnya memungkinkan Anda memberi nama fungsi anonim menggunakan properti displayName yang tersedia dalam konteks fungsi anonim saat ini. Buat profil demo berikut untuk melihat cara kerja properti displayName.

btns[0].addEventListener("click", function(e) {
    var fn = function() {
        console.log("You clicked button number: 1");
    };

    fn.displayName = "Anonymous function of button 1";

    return fn();
}, false);
Menampilkan cara kerja properti displayName.

Saat membuat profil kode dalam alat pengembangan, properti displayName akan ditampilkan, bukan (anonymous). Namun, displayName hampir mati dan tidak akan berhasil masuk ke Chrome. Namun, semua harapan tidak hilang dan proposal yang jauh lebih baik telah disarankan bernama debugName.

Pada saat penulisan, penamaan evaluasi hanya tersedia di browser Firefox dan WebKit. Properti displayName hanya ada di malam WebKit.

Mari bersatu bersama

Saat ini, ada diskusi yang sangat panjang tentang dukungan peta sumber yang ditambahkan ke CoffeeScript. Lihat masalah ini dan tambahkan dukungan Anda untuk mendapatkan pembuatan peta sumber yang ditambahkan ke compiler CoffeeScript. Hal ini akan menjadi kemenangan besar bagi CoffeeScript dan pengikutnya yang setia.

UglifyJS juga memiliki masalah peta sumber yang harus Anda lihat juga.

Banyak tools menghasilkan peta sumber, termasuk compiler coffeescript. Saya menganggap ini sebagai poin yang bisa diperdebatkan sekarang.

Semakin banyak alat yang tersedia bagi kita yang dapat membuat peta sumber, semakin baik pula hasilnya, jadi lanjutkan dan minta atau tambahkan dukungan peta sumber ke proyek sumber terbuka favorit Anda.

Ini tidak sempurna

Satu hal yang tidak dipenuhi peta sumber saat ini adalah ekspresi smartwatch. Masalahnya adalah mencoba memeriksa argumen atau nama variabel dalam konteks eksekusi saat ini tidak akan menampilkan apa pun karena tidak benar-benar ada. Hal ini akan memerlukan semacam pemetaan terbalik untuk mencari nama asli argumen/variabel yang ingin Anda periksa dibandingkan dengan nama variabel/argumen aktual dalam JavaScript yang telah Anda kompilasi.

Tentu saja ini adalah masalah yang dapat dipecahkan dan dengan lebih memperhatikan peta sumber, kita dapat mulai melihat beberapa fitur yang mengagumkan dan stabilitas yang lebih baik.

Masalah

Baru-baru ini, jQuery 1.9 menambahkan dukungan untuk peta sumber saat disalurkan dari CDN resmi. Proses ini juga menemukan bug aneh saat komentar kompilasi bersyarat IE (//@cc_on) digunakan sebelum jQuery dimuat. Sejak saat itu, ada commit untuk mengurangi hal ini dengan menggabungkan sourceMappingURL dalam komentar multibaris. Pelajaran yang akan dipelajari tidak menggunakan komentar bersyarat.

Masalah ini telah ditangani dengan perubahan sintaksis menjadi //#.

Alat dan referensi

Berikut ini beberapa referensi dan alat lain yang harus Anda pelajari:

Peta sumber adalah utilitas yang sangat canggih dalam set alat developer. Hal ini sangat berguna untuk menjaga aplikasi web Anda tetap ramping, tetapi mudah di-debug. Ini juga merupakan alat pembelajaran yang sangat canggih bagi developer baru untuk melihat cara developer berpengalaman menyusun dan menulis aplikasi mereka tanpa harus menggunakan kode mini yang tidak dapat dibaca.

Tunggu apa lagi? Mulai buat peta sumber untuk semua project sekarang.