JavaScript Kaynak Haritaları'na giriş

Ryan Seddon

İstemci taraflı kodunuzun, birleştirilip küçültüldükten sonra bile performansı etkilemeden okunabilir ve daha da önemlisi hata ayıklaması yapılabilir durumda kalmasını istediğiniz oldu mu? Artık kaynak haritaların sihirli dünyasını kullanabilirsiniz.

Kaynak haritaları, birleştirilmiş/küçültülmüş bir dosyayı oluşturulmamış bir duruma geri eşlemenin bir yoludur. Üretim için derlediğinizde, JavaScript dosyalarınızı küçültüp birleştirerek orijinal dosyalarınızla ilgili bilgileri içeren bir kaynak eşlemesi de oluşturursunuz. Oluşturulan JavaScript'inizde belirli bir satır ve sütun numarasını sorguladığınızda, kaynak eşlemede orijinal konumu döndüren bir arama yapabilirsiniz. Geliştirici araçları (şu anda WebKit gecelik derlemeler, Google Chrome veya Firefox 23+), kaynak haritasını otomatik olarak ayrıştırarak, sadeleştirilmemiş ve birleştirilmemiş dosyalar çalıştırıyormuşsunuz gibi görünmesini sağlayabilir.

Demo, oluşturulan kaynağı içeren metin alanında herhangi bir yeri sağ tıklamanıza olanak tanır. "Orijinal konumu al"ı seçtiğinizde, kaynak eşleme, oluşturulan satır ve sütun numarasını ileterek sorgulanır ve orijinal koddaki konumu döndürür. Çıkışı görebilmek için konsolunuzun açık olduğundan emin olun.

Mozilla JavaScript kaynak eşleme kitaplığının çalışma durumunu gösteren örnek.

Gerçek dünya

Kaynak Haritalar'ın aşağıdaki gerçek dünyadaki uygulamasını görüntülemeden önce, geliştirici araçları panelindeki ayarlar dişli simgesini tıklayıp "Kaynak haritalarını etkinleştir" seçeneğini işaretleyerek Chrome Canary veya WebKit'te her gece kaynak haritaları özelliğini etkinleştirdiğinizden emin olun.

WebKit geliştirici araçlarında kaynak haritaları nasıl etkinleştirilir?

Firefox 23 ve sonraki sürümler, yerleşik geliştirici araçlarında varsayılan olarak etkinleştirilen kaynak eşlemelerine sahiptir.

Firefox geliştirici araçlarında kaynak haritaları nasıl etkinleştirilir?

Kaynak haritalarına neden önem vermeliyim?

Kaynak eşleme, şu anda yalnızca sıkıştırılmamış/birleşik JavaScript ile sıkıştırılmış/birleştirilmemiş JavaScript arasında çalışmaktadır. Ancak, CoffeeScript gibi JavaScript'e derlenmiş dillerin konuşulması ve SASS veya LESS gibi CSS ön işlemcilerinin eklenmesi gibi olanaklar sayesinde gelecek çok parlak görünüyor.

Gelecekte, hemen hemen her dili, kaynak haritalarıyla tarayıcıda yerel olarak destekleniyormuş gibi kolayca kullanabiliriz:

  • CoffeeScript
  • ECMAScript 6 ve ötesi
  • SASS/DAHA AZ ve diğerleri
  • JavaScript’e derlenen hemen hemen her dil

Firefox konsolunun deneysel bir yapısında hata ayıklama işlemi yapılan CoffeeScript ekran video kaydına göz atın:

Google Web Araç Seti (GWT) kısa bir süre önce Kaynak Haritalar için destek sağlamaya başladı. GWT ekibinden Ray Cromwell, kaynak haritası desteğini uygulamalı olarak gösteren harika bir ekran video kaydı yaptı.

Birlikte sunduğum bir başka örnek, ES6 (ECMAScript 6 veya Next) yazıp ES3 uyumlu bir kodda derlemenize olanak tanıyan Google'ın Traceur kitaplığını kullanır. Traceur derleyicisi de bir kaynak eşlemesi oluşturur. Kaynak haritası sayesinde tarayıcıda yerel olarak desteklendiği gibi kullanılan ES6 özellik ve sınıflarını içeren bu demoya göz atın.

Demodaki metin alanı, anında derlenecek ES6 yazmanıza ve bir kaynak haritası ile eşdeğer ES3 kodu oluşturmanıza da olanak tanır.

Kaynak eşlemelerini kullanarak Traceur ES6 hata ayıklaması.

Demo: ES6 yazma, hata ayıklama, kaynak eşlemeyi uygulamalı olarak görüntüleme

Kaynak eşlemesi nasıl çalışır?

Şu anda kaynak haritası oluşturmak için desteği olan tek JavaScript derleyici/denetleyicisi Closure derleyicisidir. (Bunun nasıl kullanılacağını daha sonra açıklayacağım.) JavaScript'inizi birleştirip küçültdükten sonra, kaynak eşlemesi dosyasıyla birlikte görünür.

Şu anda Closure derleyicisi, tarayıcı geliştirme araçlarına bir kaynak eşlemesinin mevcut olduğunu belirtmek için gereken özel yorumu en sona eklememektedir:

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

Bu şekilde geliştirici araçları, orijinal kaynak dosyalarda aramaları kendi konumlarıyla eşleştirebilir. Önceden yorum pragması //@ idi ancak bu konu ve IE koşullu derleme yorumlarıyla ilgili bazı sorunlar nedeniyle //# olarak değiştirilmesine karar verildi. Şu anda Chrome Canary, WebKit Nightly ve Firefox 24+ yeni yorum pragma'yı desteklemektedir. Bu söz dizimi değişikliği kaynakURL'yi de etkiler.

Tuhaf açıklama hoşunuza gitmediyse derlenmiş JavaScript dosyanıza özel bir başlık da ayarlayabilirsiniz:

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

Açıklama gibi bu özellik de kaynak haritası tüketicinize, JavaScript dosyasıyla ilişkili kaynak haritasını nerede bulacağını bildirir. Bu başlık, tek satırlı yorumları desteklemeyen dillerde kaynak haritalarına referans verme sorununu da giderir.

WebKit Geliştirici Araçları örneği, açık ve kaynak eşlemelerini devre dışı bıraktı.

Kaynak eşlemesi dosyası, yalnızca kaynak eşlemelerini etkinleştirdiyseniz ve geliştirici araçlarınız açıksa indirilir. Geliştirici araçlarının gerektiğinde bunlara başvurabilmesi ve görüntüleyebilmesi için orijinal dosyalarınızı da yüklemeniz gerekir.

Kaynak eşlemesi nasıl oluşturulur?

JavaScript dosyalarınız için bir kaynak eşlemesi oluşturmak, küçültmek ve iç içe yerleştirmek için Closure derleyiciyi kullanmanız gerekir. Komut aşağıdaki gibidir:

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

İki önemli komut bayrağı --create_source_map ve --source_map_format'dir. Varsayılan sürüm V2 olduğundan bu gereklidir ve yalnızca V3 ile çalışmak isteriz.

Kaynak haritasının anatomisi

Bir kaynak eşlemesini daha iyi anlamak için, Closure derleyicisi tarafından oluşturulacak küçük bir kaynak eşleme dosyası örneğini ele alacağız ve "eşlemeler" bölümünün nasıl çalıştığıyla ilgili daha ayrıntılı bilgi vereceğiz. Aşağıdaki örnekte, V3 spesifikasyonu örneğinden küçük bir varyasyon gösterilmektedir.

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

Yukarıda bir kaynak haritasının, birçok faydalı bilgi içeren gerçek bir nesne olduğunu görebilirsiniz:

  • Kaynak eşlemesinin temel aldığı sürüm numarası
  • Oluşturulan kodun dosya adı (Küçültülmüş/birleşik üretim dosyanız)
  • sourceRoot, kaynakları bir klasör yapısıyla en başa eklemenize olanak tanır. Bu aynı zamanda bir alan tasarrufu tekniğidir.
  • kaynakları, birleştirilen tüm dosya adlarını içerir
  • adlar, kodunuzun tamamında görünen tüm değişken/yöntem adlarını içerir.
  • Son olarak, eşleme özelliği Base64 VLQ değerleri kullanılarak büyür. Gerçek alan tasarrufu burada gerçekleştirilir.

Base64 VLQ ve kaynak haritasını küçük tutma

İlk başta, kaynak haritası spesifikasyonu tüm eşlemeler için çok ayrıntılı bir çıkışa sahipti ve kaynak eşlemenin, oluşturulan kod boyutunun yaklaşık 10 katı olmasıyla sonuçlandı. İkinci sürüm bunu yaklaşık% 50 oranında azaltırken üçüncü sürüm bunu tekrar %50 oranında azalttı. Sonuç olarak 133 KB'lık bir dosya için yaklaşık 300 KB kaynak haritası elde edersiniz.

Peki, karmaşık eşlemeleri koruyarak boyutu nasıl küçülttüler?

VLQ (Değişken Uzunluk Miktarı), değeri bir Base64 değerine kodlamayla birlikte kullanılır. Eşlemeler özelliği çok büyük bir dizedir. Bu dizenin içinde, oluşturulan dosyadaki bir satır numarasını temsil eden noktalı virgüller (;) bulunur. Her satırda, içindeki her segmenti temsil eden virgüller (,) bulunur. Bu segmentlerin her biri, değişken uzunluktaki alanlarda 1, 4 veya 5'tir. Bazıları daha uzun görünebilir, ancak bunlar devam bitleri içerir. Her segment bir öncekini temel alır. Bu, her bir bit önceki segmentlere göre olduğundan dosya boyutunun azaltılmasına yardımcı olur.

Kaynak eşleme JSON dosyası içindeki bir segmentin dökümü.

Yukarıda belirtildiği gibi, her bir segment değişken uzunlukta 1, 4 veya 5 olabilir. Bu diyagram, bir devam biti (g) ve dört değişken uzunluğunda bir şema olarak kabul edilir. Bu segmenti ayıracağız ve kaynak haritanın, orijinal konum üzerinde nasıl çalıştığını göstereceğiz.

Yukarıda gösterilen değerler tamamen Base64 kodu çözülmüş değerlerdir. Doğru değerlerini almak için daha fazla işlem yapılması gerekir. Her segment genellikle beş şekilde sonuç verir:

  • Oluşturulan sütun
  • Bu öğenin göründüğü orijinal dosya
  • Orijinal satır numarası
  • Orijinal sütun
  • Varsa orijinal ad da

Her segmentin bir adı, yöntemi veya bağımsız değişkeni olmadığından, segmentlerin uzunluğu dört ila beş değişken arasında değişir. Yukarıdaki segment şemasında bulunan g değeri, Base64 VLQ kod çözme aşamasında daha fazla optimizasyona olanak tanıyan bir devam biti olarak adlandırılır. Devamlılık biti, segment değeri üzerine geliştirme yapmanıza olanak tanır. Böylece büyük sayıları depolamak zorunda kalmadan büyük sayıları depolayabilirsiniz. Bu, kökleri midi formatında olan ve yerden tasarruf etmemizi sağlayan oldukça zekice bir tekniktir.

Yukarıdaki AAgBC diyagramı daha fazla işlendiğinde 0, 0, 32, 16, 1 sonucunu döndürür. 32, aşağıdaki 16 değerinin oluşturulmasına yardımcı olan devam bitidir. Base64'te tamamen çözülmüş B, 1'dir. Bu nedenle 0, 0, 16, 1 önemli değerlerdir. Bu da bize, oluşturulan dosyadaki 1. satırdaki (satırlar noktalı virgüllerle sayı tutulur) 0. sütundaki 0 (dosya dizisi foo.js'dir), 16. satır 1. sütunda eşlendiğini bildirir.

Segmentlerin kodunun nasıl çözüldüğünü göstermek için Mozilla'nın Kaynak Haritası JavaScript kitaplığına başvuracağım. Ayrıca, JavaScript'te yazılmış WebKit geliştirici araçları kaynak eşleme koduna da bakabilirsiniz.

16 değerini B'den nasıl elde ettiğimizi doğru bir şekilde anlamak için bit tabanlı operatörler ve spesifikasyonun kaynak eşlemede nasıl çalıştığıyla ilgili temel bilgilere sahip olmamız gerekir. Önceki basamak (g), bit tabanlı AND (&) operatörü kullanılarak rakam (32) ile VLQ_CONTINUATION_BIT (ikili 100000 veya 32) karşılaştırılarak devam biti olarak işaretlenir.

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

Bu, her ikisinin de göründüğü her bit konumunda 1 döndürür. Dolayısıyla, Base64 kodu çözülmüş bir 33 & 32 değeri, yukarıdaki şemada görebileceğiniz gibi yalnızca 32 bit konumu paylaştığından 32 değerini döndürür. Böylece, önceki her devam biti için bit kaydırma değeri 5 artar. Yukarıdaki örnekte yalnızca bir kez 5 kaydırıldığı için 1 (B) x 5 kaydırılmıştır.

1 <<../ 5 // 32

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

Bu değer daha sonra, sayının (32) bir nokta sağa kaydırılmasıyla VLQ imzalı değerden dönüştürülür.

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

Hepsi bu kadar. 1'i 16'ya bu şekilde dönüştürebilirsiniz. Bu süreç karmaşık görünebilir ancak sayıların büyümeye başlaması daha mantıklı olacaktır.

Olası XSSI sorunları

Spesifikasyonda, kaynak eşlemesinin kullanımından ortaya çıkabilecek siteler arası komut dosyası dahil etme sorunları belirtilir. Bu durumu azaltmak amacıyla, JavaScript'i kasıtlı olarak geçersiz kılmak için kaynak eşlemenizin ilk satırının başına ")]}" eklemeniz önerilir. Böylece söz dizimi hatası verilir. WebKit geliştirici araçları bunu zaten halledebilir.

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

Yukarıda gösterildiği gibi ilk üç karakter, spesifikasyondaki söz dizimi hatasıyla eşleşip eşleşmediklerinin kontrol edilmesi için dilimlenir ve varsa ilk yeni satır öğesine (\n) giden tüm karakterler kaldırılır.

sourceURL ve displayName iş başında: Değerlendirme ve anonim işlevler

Kaynak eşleme spesifikasyonunun bir parçası olmasa da aşağıdaki iki kural, değerlendirmeler ve anonim işlevlerle çalışırken geliştirme sürecini çok daha kolay hale getirmenizi sağlar.

İlk yardımcı, //# sourceMappingURL mülküne çok benzer ve aslında kaynak haritası V3 spesifikasyonunda belirtilir. Gözden geçirilecek aşağıdaki özel yorumu kodunuza ekleyerek, geliştirme araçlarınızda daha mantıksal adlar olarak görünmeleri için değerlendirmeleri adlandırabilirsiniz. CoffeeScript derleyicisini kullanarak basit bir demoya göz atın:

Demo: eval() kodunu sourceURL aracılığıyla bir komut dosyası olarak görün

//# sourceURL=sqrt.coffee
sourceURL özel yorumu, geliştirici araçlarında nasıl görünür?

Diğer yardımcı, anonim işlevin geçerli bağlamında bulunan displayName özelliğini kullanarak anonim işlevleri adlandırmanıza olanak tanır. displayName mülkünün nasıl çalıştığını görmek için aşağıdaki demoda profil oluşturun.

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);
displayName mülkünü çalışırken gösteriyor.

Geliştirici araçlarında kodunuzun profilini oluştururken (anonymous) gibi bir değer yerine displayName özelliği gösterilir. Ancak, displayName dediğiniz halde artık Chrome'a eklenmez. Ancak tüm umutlar kaybolmadı ve debugName adlı çok daha iyi bir teklif önerildi.

Değerlendirme adının yazılması yalnızca Firefox ve WebKit tarayıcılarda kullanılabilir. displayName mülkü yalnızca WebKit geceleri için geçerlidir.

Birlikte harekete geçelim

Şu anda CoffeeScript'e eklenen kaynak haritası desteği hakkında çok uzun tartışmalar devam etmektedir. Soruna göz atın ve kaynak eşleme oluşturma işleminin CoffeeScript derleyicisine eklenmesi için desteğinizi ekleyin. Bu, CoffeeScript ve sadık takipçileri için büyük bir kazanç olacak.

UglifyJS'nin de incelemeniz gereken bir kaynak eşlemesi sorunu vardır.

Coffeescript derleyicisi de dahil olmak üzere birçok tools kaynak haritaları oluşturur. Bunu artık bir itiraz noktası olarak görüyorum.

Kaynak haritaları oluşturabilecek araç sayısını ne kadar çok alırsak o kadar iyi olur. Bu nedenle, devam edip en sevdiğiniz açık kaynak projenize kaynak haritası desteği isteyin veya ekleyin.

Mükemmel değil

Kaynak haritalarında şu an için yeterli olmayan işlevlerden biri de izleme ifadeleridir. Sorun, bir bağımsız değişkeni veya değişken adını geçerli yürütme bağlamı içinde denetlemeye çalışmanın aslında var olmadığı için hiçbir sonuç döndürmeyecek olmasıdır. Bu, incelemek istediğiniz bağımsız değişkenin/değişkenin gerçek adını, derlenmiş JavaScript'inizdeki gerçek bağımsız değişken/değişken adıyla karşılaştırabilmek için bir tür ters eşleme gerektirir.

Bu elbette, çözülebilir bir sorundur ve kaynak haritalarına daha fazla dikkat çekerek bazı harika özellikler ve daha iyi kararlılık görmeye başlayabiliriz.

Sorunlar

Kısa süre önce jQuery 1.9, resmi CDN'ler dışında sunulduğunda kaynak eşlemeleri için destek eklemiştir. Ayrıca, jQuery yüklenmeden önce IE koşullu derleme yorumları (//@cc_on) kullanıldığında benzersiz bir hataya işaret etti. O zamandan beri sourceEşlemeURL'sini çok satırlı bir yoruma sarmalayarak bu sorunu azaltmak için taahhüt ediliyor. Alınacak ders, koşullu yorumlar kullanmayın.

O zamandan beri, söz diziminin //# olarak değiştirilmesiyle bu sorun giderildi.

Araçlar ve kaynak

Göz atmanız gereken diğer kaynaklar ve araçlar şunlardır:

  • Nick Fitzgerald'ın, kaynak harita desteği sunan bir UglifyJS çatalı var
  • Paul Ireland, kaynak haritalarını gösteren küçük bir demo sunuyor
  • Bu özelliğin ne zaman kaldırıldığına ilişkin WebKit değişiklik kümesine göz atın
  • Değişiklik kümesi, tüm bu makalenin başlamasını sağlayan bir düzen testi de içeriyordu.
  • Mozilla'nın yerleşik konsolda kaynak eşlemelerinin durumuyla ilgili takip etmeniz gereken bir hata vardır
  • Conrad Irwin, tüm Ruby kullanıcılarınız için son derece kullanışlı bir kaynak harita cevheri yazdı
  • Eval adlandırma ve displayName mülkü ile ilgili daha fazla bilgi edinin.
  • Kaynak haritaları oluşturmak için Closure Derleyiciler kaynağına göz atabilirsiniz.
  • Bazı ekran görüntüleri ve GWT kaynak haritaları desteğinden bahsedilmektedir.

Kaynak haritaları, bir geliştiricinin araç setinde çok güçlü bir yardımcı programdır. Web uygulamanızı basit ancak hata ayıklaması kolayca yapılabilir durumda tutabilmek son derece yararlıdır. Ayrıca, yeni geliştiricilerin, okunamayan ve küçültülmüş kodlarla uğraşmak zorunda kalmadan, deneyimli geliştiricilerin nasıl yapılandırdıklarını ve uygulamalarını nasıl yazdıklarını görebilecekleri çok güçlü bir öğrenim aracıdır.

Neyi bekliyorsunuz? Hemen tüm projeler için kaynak haritaları oluşturmaya başlayın!