JavaScript Kaynak Haritaları'na giriş

Ryan Seddon

Kodu birleştirdikten ve küçülttikten sonra bile performansı etkilemeden istemci tarafı kodunuzu okunabilir ve daha da önemlisi hata ayıklanabilir durumda tutabilmeyi istediğiniz oldu mu? Bunu kaynak haritaların sihriyle yapabilirsiniz.

Kaynak eşlemeleri, birleştirilmiş/küçültülmüş bir dosyayı henüz oluşturulmamış duruma eşlemenin bir yoludur. Üretim için derleme yaptığınızda, JavaScript dosyalarınızı küçültüp birleştirerek orijinal dosyalarınızla ilgili bilgileri içeren bir kaynak haritası oluşturursunuz. Oluşturulan JavaScript'inizde belirli bir satır ve sütun numarasını sorguladığınızda, kaynak haritada orijinal konumu döndüren bir arama yapabilirsiniz. Geliştirici araçları (şu anda WebKit'in gecelik derlemeleri, Google Chrome veya Firefox 23 ve sonraki sürümler), kaynak haritayı otomatik olarak ayrıştırıp sadeleştirilmemiş ve birleştirilmemiş dosyalar çalışıyormuş 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, oluşturulan satır ve sütun numarasını girerek kaynak eşlemeyi sorgular ve konumu orijinal kodda döndürür. Sonucu görebilmek için konsolunuzun açık olduğundan emin olun.

Mozilla JavaScript kaynak haritası kitaplığının işleyiş şeklini gösteren örnek.

Gerçek dünya

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

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

Firefox 23 ve sonraki sürümlerde, yerleşik geliştirme araçlarında varsayılan olarak etkinleştirilmiş kaynak haritaları bulunur.

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

Kaynak eşlemelerini neden önemsemeliyim?

Kaynak eşleme, şu anda yalnızca sıkıştırılmamış/birleştirilmiş JavaScript'ten sıkıştırılmış/birleştirilmemiş JavaScript'e kadar çalışıyor. Ancak CoffeeScript gibi derlenmiş JavaScript dilleri ve hatta SASS veya LESS gibi CSS ön işlemcileri için destek ekleme olanağı sayesinde gelecek daha parlak bir gelecek.

İleride, kaynak eşlemeleriyle tarayıcıda yerel olarak destekleniyormuş gibi hemen hemen her dili kolayca kullanabilecektik:

  • CoffeeScript
  • ECMAScript 6 ve sonrası
  • SASS/LESS ve diğerleri
  • JavaScript'e derleme yapan tüm diller

Firefox konsolunun deneysel bir derlemesinde hata ayıklama işlemi yapılan CoffeeScript'in şu ekran video kaydını inceleyin:

Google Web Araç Seti (GWT) kısa bir süre önce Kaynak Haritalar için destek ekledi. GWT ekibinden Ray Cromwell, kaynak harita desteğini çalışırken gösteren harika bir ekran video kaydı yaptı.

Oluşturduğum bir başka örnekte, ES6 (ECMAScript 6 veya Next) yazmanıza ve ES3 ile uyumlu kod olarak derlemenize olanak tanıyan Google Traceur kitaplığı kullanılmıştır. Traceur derleyicisi, bir kaynak haritası da oluşturur. Kaynak eşleme sayesinde tarayıcıda yerel olarak desteklendikleri gibi kullanılan ES6 özelliklerinin ve sınıflarının demosunu inceleyin.

Demodaki metin alanı, anında derlenecek ve bir kaynak harita ile eşdeğer ES3 kodu oluşturacak ES6 yazmanıza 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 harita oluşturma desteği olan tek JavaScript derleyici/küçültücü Closure derleyici'dir. (Bunu nasıl kullanacağınızı daha sonra açıklayacağım.) JavaScript'iniz birleştirilip küçültüldükten sonra, yanında bir kaynak eşleme dosyası bulunur.

Şu anda Closure derleyici, tarayıcı geliştirici araçlarına bir kaynak eşlemenin mevcut olduğunu belirtmek için gerekli özel yorumu sona eklememektedir:

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

Bu, geliştirici araçlarının çağrıları orijinal kaynak dosyalardaki konumlarına geri eşleştirmesini sağlar. Daha önce yorum pragması //@ şeklindeydi, ancak bununla ilgili bazı sorunlar ve IE koşullu derleme yorumları nedeniyle, yorumun //# olarak değiştirilmesine karar verildi. Şu an için Chrome Canary, WebKit Nightly ve Firefox 24 ve sonraki sürümler yeni yorum pragmasını desteklemektedir. Bu söz dizimi değişikliği, sourceURL'yi de etkiler.

Tuhaf yorum fikrini beğenmediyseniz, derlenmiş JavaScript dosyanızda özel bir başlık da ayarlayabilirsiniz:

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

Yorumda olduğu gibi bu, kaynak harita tüketicinize bir JavaScript dosyasıyla ilişkilendirilmiş kaynak haritayı nerede arayacağını bildirir. Bu başlık, tek satırlı yorumları desteklemeyen dillerde kaynak eşlemelerine referans verme sorununu da ele alır.

WebKit Devtools kaynak eşleme örneği, kapalı kaynak eşleme örneği.

Kaynak harita dosyası, yalnızca kaynak eşlemeleri etkinse ve geliştirici araçlarınız açıksa indirilir. Ayrıca, geliştirici araçlarının gerektiğinde bu dosyalara 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ı küçültmek, birleştirmek ve kaynak haritası oluşturmak için Closure derleyici'yi 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

--create_source_map ve --source_map_format, iki önemli komut işaretidir. Varsayılan sürüm V2 olduğundan ve yalnızca V3 ile çalışmak istediğimizden bu gereklidir.

Bir kaynak haritasının anatomisi

Bir kaynak haritasını daha iyi anlamak için Closure derleyicisi tarafından oluşturulacak bir kaynak harita dosyasının küçük bir örneğini kullanacağız ve "eşlemeler" bölümünün nasıl çalıştığını daha ayrıntılı olarak ele alacağız. Aşağıdaki örnekte, V3 spesifikasyonu örneğindeki 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, kaynak haritasının çok sayıda ilginç bilgi içeren bir nesne değişmez olduğunu görebilirsiniz:

  • Kaynak eşlemenin temel aldığı sürüm numarası
  • Oluşturulan kodun dosya adı (Küçültülmüş/kombine üretim dosyanız)
  • sourceRoot, kaynakları bir klasör yapısıyla eklemenizi sağlar. Bu aynı zamanda yer 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şlemeler özelliğinde asıl işlem Base64 VLQ değerleri kullanılarak gerçekleşir. Gerçek alan tasarrufu burada gerçekleştirilir.

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

İlk başta, kaynak harita spesifikasyonu tüm eşlemelerin çok ayrıntılı çıktılarını içeriyordu ve kaynak eşlemenin, oluşturulan kod boyutunun yaklaşık 10 katı boyutunu içermesiyle sonuçlanıyordu. İkinci sürüm ise bu oranı yaklaşık% 50, üçüncü sürüm ise bir kez daha %50 azalttı. Dolayısıyla 133 kB'lık bir dosya için 300 kB'lık bir kaynak eşleme elde ettiniz.

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

VLQ (Değişken Uzunluk Miktarı) değeri, değerin bir Base64 değerine kodlanmasıyla birlikte kullanılır. Eşlemeler özelliği çok büyük bir dizedir. Bu dizenin içinde, oluşturulan dosyanın içindeki bir satır numarasını temsil eden noktalı virgüller (;) bulunur. Her satırda, bu satırdaki 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 devamlılık bitleri içerir. Her segment bir öncekinin üzerine inşa edilir. Bu, her bir bit önceki segmentlerine göre olduğundan dosya boyutunun azaltılmasına yardımcı olur.

Kaynak harita JSON dosyası içindeki bir segmentin dökümü.

Yukarıda belirtildiği gibi, her segment değişken uzunlukta 1, 4 veya 5 olabilir. Bu diyagramda, bir devam biti (g) bulunan ve dört uzunluğunda değişken olarak kabul edilir. Bu segmenti ayrıntılarıyla inceleyeceğiz ve kaynak haritasını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 elde etmek için birkaç işlem daha yapılması gerekir. Her segment genellikle beş şey yapar:

  • Oluşturulan sütun
  • Bunun göründüğü orijinal dosya
  • Orijinal satır numarası
  • Orijinal sütun
  • Varsa asıl adı

Her segmentin adı, yöntem adı veya bağımsız değişkeni yoktur. Bu nedenle, tüm segmentler dört ila beş değişken uzunluğu arasında geçiş yapar. Yukarıdaki segment şemasında yer alan g değerine devamlılık biti denir ve Base64 VLQ kod çözme aşamasında daha fazla optimizasyon yapılmasını sağlar. Bir devamlı işlem biti, bir segment değeri üzerinde derlemenizi sağlar. Böylece, büyük bir sayıyı depolamak zorunda kalmadan büyük sayıları depolayabilirsiniz. Bu, kökleri midi biçiminde olan çok akıllı bir alan tasarrufu tekniğidir.

Yukarıdaki AAgBC şeması daha fazla işlendiğinde 0, 0, 32, 16, 1 sonucunu döndürür. 32, aşağıdaki 16 değerini oluşturmaya yardımcı olan devam bitidir. Base64'te tamamen çözülen B, 1'dir. Bu nedenle, kullanılan önemli değerler 0, 0, 16, 1'dir. Bu, oluşturulan dosyanın 1. satırının (satırların sayısı noktalı iki nokta üst üste ile verilir) sütun 0'ın dosya 0 (0 dosya dizisi foo.js'dir), 1. sütundaki 16. satır ile eşlendiğini anlamamızı sağlar.

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

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

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

Bu, her ikisinde de göründüğü her bit konumunda 1 döndürür. Dolayısıyla, 33 & 32 öğesinin kodu çözülmüş bir Base64 değeri, yukarıdaki şemada görebileceğiniz gibi yalnızca 32 bit konumunu paylaştığından 32 döndürür. Bu işlem daha sonra, önceki her devamlılık biti için bit kaydırma değerini 5 artırır. Yukarıdaki örnekte yalnızca 5 bir kez kaydırılmıştır. Dolayısıyla sola kaydırarak 1 (B) x 5 kaydırabilirsiniz.

1 <<../ 5 // 32

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

Daha sonra bu değer, sayının (32) bir noktasında sağa kaydırılarak VLQ imzalı bir değerden dönüştürülür.

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

İşte oldu. 1'i böyle 16'ya çeviriyorsunuz. Bu, aşırı karmaşık bir süreç gibi görünebilir, ancak sayılar büyüdükçe daha da anlamlı hale gelir.

Olası XSSI sorunları

Bu spesifikasyonda, bir kaynak eşlemenin kullanılmasından kaynaklanabilecek siteler arası komut dosyası ekleme sorunlarından bahsedilmektedir. Bu sorunu 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ı oluşur. WebKit geliştirici araçları bu sorunların üstesinden gelebilir.

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şmediklerini kontrol etmek için dilimlenir. Bu durumda ilk yeni satır öğesine (\n) giden tüm karakterler kaldırılır.

sourceURL ve displayName iş başında: Eval ve anonim işlevler

Kaynak eşlemenin bir parçası olmasa da aşağıdaki iki kural, değerlendirmeler ve anonim işlevlerle çalışırken geliştirmeyi çok daha kolay hale getirmenize olanak tanır.

İlk yardımcı, //# sourceMappingURL özelliğine çok benziyor ve aslında kaynak harita V3 spesifikasyonunda belirtiliyor. Kodunuza atılacak aşağıdaki özel yorumu ekleyerek değerlendirmeleri adlandırabilirsiniz. Böylece geliştirme araçlarınızda bunların daha mantıklı adlar olarak görünmesini sağlayabilirsiniz. CoffeeScript derleyicisini kullanan basit bir demoya göz atın:

Demo: eval()'deki kodu sourceURL üzerinden komut dosyası olarak gösterin

//# 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 demonun profilini inceleyin.

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 özelliğinin işleyiş şeklini gösteriyor.

Geliştirici araçlarında kodunuzun profilini çıkarırken (anonymous) gibi bir değer yerine displayName özelliği gösterilir. Ancak displayName suda neredeyse ölmüştür ve Chrome'a girmeyecektir. Ancak tüm umutlar kaybolmamış ve debugName adı verilen çok daha iyi bir teklif önerildi.

Eval adlandırma şu an için yalnızca Firefox ve WebKit tarayıcılarda kullanılabilmektedir. displayName özelliği yalnızca WebKit gecelerinde kullanılabilir.

Birlikte toplanalım

Şu anda CoffeeScript'e eklenen kaynak harita desteği ile ilgili çok uzun bir tartışma mevcuttur. Sorunu inceleyin ve CoffeeScript derleyicisine kaynak harita oluşturma işleminin eklenmesi için desteğinizi ekleyin. Bu, CoffeeScript ve sadık takipçileri için büyük bir kazanç olacak.

UglifyJS'nin ilgilenmeniz gereken bir kaynak harita sorunu da var.

Coffeescript derleyicisi de dahil olmak üzere birçok tools, kaynak eşlemeleri oluşturur. Bu konuyu şu an için bir tartışma noktası olarak görüyorum.

Kaynak haritaları oluşturabilecek ne kadar çok araç elimizde varsa o kadar iyi olacaktır. O yüzden sorun ve favori açık kaynak projenize kaynak harita desteği ekleyin.

Mükemmel değil

Kaynak haritalarında şu anda izleme ifadelerine yer verilmemektedir. Sorun, bir bağımsız değişkeni veya değişken adını geçerli yürütme bağlamı içinde incelemeye çalışmanın, gerçekte var olmadığı için hiçbir şey döndürmemesidir. Bu, derlenen JavaScript'inizdeki gerçek bağımsız değişken/değişken adıyla karşılaştırıldığında incelemek istediğiniz bağımsız değişkenin/değişkenin gerçek adını aramak için bir tür ters eşleme gerektirir.

Bu tabii ki çözülebilir bir sorun ve kaynak haritalarına daha fazla dikkat ettiğimizde muhteşem özellikler ve daha istikrarlı hale gelmeye başlayabiliriz.

Sorunlar

Kısa bir süre önce jQuery 1.9, resmi CDN'lerin 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 özel bir hataya işaret etti. O zamandan beri, source Eşleme URL'sini çok satırlı bir yoruma sarmalayarak bu sorunun etkilerini hafifletmek için taahhüt yapılmıştır. Alınacak ders, koşullu yorum kullanmayın.

O zamandan beri bu sorun düzeltildi ve söz dizimi //# olarak değiştirildi.

Araçlar ve kaynak

İşte göz atmanız gereken diğer kaynak ve araçlardan bazıları:

Kaynak haritaları geliştirici araç setinde kullanabileceğiniz çok güçlü bir yardımcı programdır. Web uygulamanızı sade ama kolay hata ayıklamaya uygun hale getirmek son derece yararlıdır. Ayrıca yeni geliştiricilerin, deneyimli geliştiricilerin okunamayan küçültülmüş kodlarla uğraşmak zorunda kalmadan uygulamalarını nasıl yapılandırıp yazdıklarını görmelerini sağlayan çok güçlü bir öğrenme aracıdır.

Neyi bekliyorsunuz? Hemen tüm projeler için kaynak eşlemeleri oluşturmaya başlayın.