İleri Derleme

Genel Bakış

compilation_level ile ADVANCED_OPTIMIZATIONS kullanarak Closure Compiler'ı kullanmak, SIMPLE_OPTIMIZATIONS veya WHITESPACE_ONLY ile derlemeye kıyasla daha iyi sıkıştırma oranları sunar. ADVANCED_OPTIMIZATIONS ile derleme, kodu dönüştürme ve sembolleri yeniden adlandırma yöntemlerinde daha agresif davranarak ek sıkıştırma sağlar. Ancak bu daha agresif yaklaşım, ADVANCED_OPTIMIZATIONS kullanırken daha dikkatli olmanız gerektiği anlamına gelir. Bu sayede çıkış kodunun giriş koduyla aynı şekilde çalıştığından emin olabilirsiniz.

Bu eğiticide, ADVANCED_OPTIMIZATIONS derleme düzeyinin ne yaptığı ve ADVANCED_OPTIMIZATIONS ile derleme işleminden sonra kodunuzun çalıştığından emin olmak için neler yapabileceğiniz açıklanmaktadır. Ayrıca, derleyici tarafından işlenen kodun dışında tanımlanan bir sembol olan extern kavramını da tanıtır.

Bu eğitimi okumadan önce, Java tabanlı derleyici uygulaması gibi Closure Compiler araçlarından biriyle JavaScript'i derleme sürecine aşina olmanız gerekir.

Terminolojiyle ilgili bir not: --compilation_level komut satırı işareti, daha yaygın olarak kullanılan kısaltmalar ADVANCED ve SIMPLE ile daha hassas olan ADVANCED_OPTIMIZATIONS ve SIMPLE_OPTIMIZATIONS kısaltmalarını destekler. Bu belgede daha uzun biçim kullanılmaktadır ancak komut satırında adlar birbirinin yerine kullanılabilir.

  1. Daha da İyi Sıkıştırma
  2. Nasıl yapılır? ADVANCED_OPTIMIZATIONS'ı etkinleştirme
  3. ADVANCED_OPTIMIZATIONS Kullanırken Dikkat Edilmesi Gerekenler
    1. Tutmak istediğiniz kodun kaldırılması
    2. Tutarsız Tesis Adları
    3. İki Kod Bölümünü Ayrı Ayrı Derleme
    4. Derlenmiş ve Derlenmemiş Kod Arasındaki Bozuk Referanslar

Even Better Compression

Closure Compiler, SIMPLE_OPTIMIZATIONS varsayılan derleme düzeyiyle yerel değişkenleri yeniden adlandırarak JavaScript'i küçültür. Yerel değişkenler dışında kısaltılabilecek semboller ve sembolleri yeniden adlandırmak dışında kodu küçültmenin yolları vardır. ADVANCED_OPTIMIZATIONS ile derleme, kod küçültme olanaklarının tümünden yararlanır.

Aşağıdaki kod için SIMPLE_OPTIMIZATIONS ve ADVANCED_OPTIMIZATIONS çıkışlarını karşılaştırın:

function unusedFunction(note) {
  alert(note['text']);
}

function displayNoteTitle(note) {
  alert(note['title']);
}

var flowerNote = {};
flowerNote['title'] = "Flowers";
displayNoteTitle(flowerNote);

SIMPLE_OPTIMIZATIONS ile derleme, kodu şu şekilde kısaltır:

function unusedFunction(a){alert(a.text)}function displayNoteTitle(a){alert(a.title)}var flowerNote={};flowerNote.title="Flowers";displayNoteTitle(flowerNote);

ADVANCED_OPTIMIZATIONS ile derleme, kodu tamamen kısaltarak şu hale getirir:

alert("Flowers");

Bu iki komut dosyası da "Flowers" uyarısını verir ancak ikinci komut dosyası çok daha küçüktür.

ADVANCED_OPTIMIZATIONS düzeyi, değişken adlarının basitçe kısaltılmasının ötesine geçerek çeşitli avantajlar sunar. Örneğin:

  • daha agresif yeniden adlandırma:

    Yalnızca SIMPLE_OPTIMIZATIONS ile derleme displayNoteTitle() ve unusedFunction() işlevlerinin note parametrelerini yeniden adlandırır. Bunun nedeni, komut dosyasındaki işlevlere yerel olan tek değişkenlerin bunlar olmasıdır. ADVANCED_OPTIMIZATIONS, global değişkeni de yeniden adlandırır flowerNote.

  • Ölü kod kaldırma:

    ADVANCED_OPTIMIZATIONS ile derleme, kodda hiçbir zaman çağrılmadığı için unusedFunction() işlevini tamamen kaldırır.

  • işlev satır içi yerleştirme:

    ADVANCED_OPTIMIZATIONS ile derleme, displayNoteTitle() işlevine yapılan çağrıyı, işlevin gövdesini oluşturan tek alert() ile değiştirir. Bir işlev çağrısının işlevin gövdesiyle değiştirilmesine "satır içi genişletme" adı verilir. İşlev daha uzun veya daha karmaşık olsaydı satır içi yapılması kodun davranışını değiştirebilirdi ancak Closure Compiler bu durumda satır içi yapmanın güvenli olduğunu ve yer kazandırdığını belirler. Derleme, ADVANCED_OPTIMIZATIONS ile birlikte sabitleri ve bazı değişkenleri güvenli bir şekilde yapabileceğini belirlediğinde satır içine de yerleştirir.

Bu liste, ADVANCED_OPTIMIZATIONS derlemesinin gerçekleştirebileceği boyut küçültme dönüşümlerinin yalnızca bir örneğidir.

ADVANCED_OPTIMIZATIONS nasıl etkinleştirilir?

Closure Compiler uygulaması için ADVANCED_OPTIMIZATIONS özelliğini etkinleştirmek üzere komut satırı işaretini --compilation_level ADVANCED_OPTIMIZATIONS aşağıdaki komuttaki gibi ekleyin:

java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js hello.js

ADVANCED_OPTIMIZATIONS Kullanırken Dikkat Edilmesi Gerekenler

ADVANCED_OPTIMIZATIONS ile ilgili sık karşılaşılan bazı istenmeyen etkiler ve bunları önlemek için uygulayabileceğiniz adımlar aşağıda listelenmiştir.

Saklamak istediğiniz kodun kaldırılması

Aşağıdaki işlevi yalnızca ADVANCED_OPTIMIZATIONS ile derlerseniz Closure Compiler boş bir çıkış üretir:

function displayNoteTitle(note) {
  alert(note['myTitle']);
}

Derleyiciye ilettiğiniz JavaScript'te işlev hiçbir zaman çağrılmadığı için Closure Compiler, bu kodun gerekli olmadığını varsayar.

Çoğu durumda bu davranış tam olarak istediğiniz şeydir. Örneğin, kodunuzu büyük bir kitaplıkla birlikte derlerseniz Closure Compiler, bu kitaplıktaki hangi işlevleri kullandığınızı belirleyebilir ve kullanmadığınız işlevleri atabilir.

Ancak Closure Compiler'ın tutmak istediğiniz işlevleri kaldırdığını fark ederseniz bunu önlemenin iki yolu vardır:

  • İşlev çağrılarınızı Closure Compiler tarafından işlenen koda taşıyın.
  • Dışa aktarmak istediğiniz işlevler için harici dosyaları ekleyin.

Sonraki bölümlerde her seçenek daha ayrıntılı olarak ele alınmaktadır.

Çözüm: İşlev çağrılarınızı Closure Compiler tarafından işlenen koda taşıyın

Kodunuzun yalnızca bir bölümünü Closure Compiler ile derlerseniz istenmeyen kod kaldırma işlemiyle karşılaşabilirsiniz. Örneğin, yalnızca işlev tanımlarını içeren bir kitaplık dosyanız ve kitaplığı içeren ve bu işlevleri çağıran kodu içeren bir HTML dosyanız olabilir. Bu durumda, kitaplık dosyasını ADVANCED_OPTIMIZATIONS ile derlerseniz Closure Compiler, tüm kitaplık işlevlerinizi kaldırır.

Bu sorunun en basit çözümü, işlevlerinizi bu işlevleri çağıran programınızın bölümüyle birlikte derlemektir. Örneğin, Closure Compiler aşağıdaki programı derlerken displayNoteTitle() öğesini kaldırmaz:

function displayNoteTitle(note) {
  alert(note['myTitle']);
}
displayNoteTitle({'myTitle': 'Flowers'});

Bu durumda displayNoteTitle() işlevi, Closure Compiler tarafından çağrıldığı görüldüğü için kaldırılmaz.

Başka bir deyişle, programınızın giriş noktasını Closure Compiler'a ilettiğiniz koda ekleyerek istenmeyen kod kaldırma işlemini önleyebilirsiniz. Bir programın giriş noktası, programın yürütülmeye başladığı kod bölümüdür. Örneğin, önceki bölümdeki çiçek notu programında son üç satır, JavaScript tarayıcıya yüklendiği anda yürütülür. Bu programın giriş noktasıdır. Hangi kodu saklamanız gerektiğini belirlemek için Closure Compiler bu giriş noktasından başlar ve programın kontrol akışını buradan itibaren ileriye doğru izler.

Çözüm: Kullanıma sunmak istediğiniz işlevler için Externs'i dahil edin

Bu çözüm hakkında daha fazla bilgiyi aşağıda ve stajyerler ve dışa aktarmalar sayfasında bulabilirsiniz.

Tutarsız Tesis Adları

Closure Compiler derlemesi, hangi derleme düzeyini kullanırsanız kullanın kodunuzdaki dize değişmezlerini asla değiştirmez. Bu, ADVANCED_OPTIMIZATIONS ile derlemenin, kodunuzun özelliklere dizeyle erişip erişmediğine bağlı olarak özellikleri farklı şekilde ele aldığı anlamına gelir. Bir mülke yönelik dize referanslarını nokta söz dizimi referanslarıyla karıştırırsanız Closure Compiler, bu mülke yönelik referansların bazılarını yeniden adlandırır ancak diğerlerini yeniden adlandırmaz. Bu nedenle, kodunuz büyük olasılıkla doğru şekilde çalışmayacaktır.

Örneğin, aşağıdaki kodu ele alalım:

function displayNoteTitle(note) {
  alert(note['myTitle']);
}
var flowerNote = {};
flowerNote.myTitle = 'Flowers';

alert(flowerNote.myTitle);
displayNoteTitle(flowerNote);

Bu kaynak kodundaki son iki ifade tam olarak aynı şeyi yapar. Ancak kodu ADVANCED_OPTIMIZATIONS ile sıkıştırdığınızda şu sonuç elde edilir:

var a={};a.a="Flowers";alert(a.a);alert(a.myTitle);

Sıkıştırılmış koddaki son ifade hata veriyor. myTitle özelliğine doğrudan referans a olarak yeniden adlandırıldı ancak displayNoteTitle işlevi içindeki myTitle özelliğine yapılan alıntılanmış referans yeniden adlandırılmadı. Bu nedenle, son ifade artık mevcut olmayan bir myTitle mülküne atıfta bulunuyor.

Çözüm: Mülk Adlarınızda Tutarlı Olun

Bu çözüm oldukça basittir. Belirli bir tür veya nesne için yalnızca nokta söz dizimini ya da tırnak içine alınmış dizeleri kullanın. Söz dizimlerini karıştırmayın. Özellikle aynı özelliklere referans verirken bu kurala uyun.

Ayrıca, mümkün olduğunda nokta söz dizimini kullanmayı tercih edin. Bu söz dizimi, daha iyi kontrolleri ve optimizasyonları destekler. Alıntılanmış dize özelliği erişimini yalnızca Closure Compiler'ın yeniden adlandırma yapmasını istemediğiniz durumlarda kullanın. Örneğin, adın kod çözümü yapılmış JSON gibi harici bir kaynaktan geldiği durumlarda bu yöntemi kullanabilirsiniz.

İki kod bölümünü ayrı ayrı derleme

Uygulamanızı farklı kod parçalarına bölerseniz parçaları ayrı ayrı derlemek isteyebilirsiniz. Ancak iki kod parçası etkileşime giriyorsa bu durum zorluklara neden olabilir. Başarılı olsanız bile iki Closure Compiler çalıştırmasının çıktısı uyumlu olmaz.

Örneğin, bir uygulamanın iki bölüme ayrıldığını varsayalım: verileri alan bir bölüm ve verileri görüntüleyen bir bölüm.

Verileri almak için kullanılan kod aşağıda verilmiştir:

function getData() {
  // In an actual project, this data would be retrieved from the server.
  return {title: 'Flower Care', text: 'Flowers need water.'};
}

Verileri görüntülemek için kullanılan kod aşağıda verilmiştir:

var displayElement = document.getElementById('display');
function displayData(parent, data) {
  var textElement = document.createTextNode(data.text);
  parent.appendChild(textElement);
}
displayData(displayElement, getData());

Bu iki kod parçasını ayrı ayrı derlemeye çalışırsanız çeşitli sorunlarla karşılaşırsınız. Öncelikle Closure Compiler, getData() işlevini Removal of Code You Want to Keep (Tutmak İstediğiniz Kodun Kaldırılması) bölümünde açıklanan nedenlerle kaldırır. İkincisi, Closure Compiler, verileri görüntüleyen kodu işlerken ölümcül bir hata üretiyor.

input:6: ERROR - variable getData is undefined
displayData(displayElement, getData());

Derleyici, verileri gösteren kodu derlerken getData() işlevine erişemediği için getData öğesini tanımlanmamış olarak değerlendirir.

Çözüm: Bir Sayfadaki Tüm Kodları Birlikte Derleyin

Doğru derleme için bir sayfanın tüm kodunu tek bir derleme çalıştırmasında birlikte derleyin. Closure Compiler, giriş olarak birden fazla JavaScript dosyası ve JavaScript dizesi kabul edebilir. Bu nedenle, kitaplık kodunu ve diğer kodları tek bir derleme isteğinde birlikte iletebilirsiniz.

Not: Derlenmiş ve derlenmemiş kodu karıştırmanız gerekiyorsa bu yaklaşım işe yaramaz. Bu durumu ele alma hakkında ipuçları için Derlenmiş ve Derlenmemiş Kod Arasındaki Bozuk Referanslar bölümüne bakın.

Derlenmiş ve Derlenmemiş Kod Arasındaki Bozuk Referanslar

ADVANCED_OPTIMIZATIONS içinde sembol yeniden adlandırma, Closure Compiler tarafından işlenen kod ile diğer tüm kodlar arasındaki iletişimi bozar. Derleme, kaynak kodunuzda tanımlanan işlevleri yeniden adlandırır. İşlevlerinizi çağıran tüm harici kodlar, derleme işleminden sonra bozulur. Bunun nedeni, bu kodların hâlâ eski işlev adına başvurmasıdır. Benzer şekilde, derlenmiş koddaki harici olarak tanımlanmış sembollere yapılan referanslar da Closure Compiler tarafından değiştirilebilir.

"Derlenmemiş kod"un, eval() işlevine dize olarak iletilen tüm kodları içerdiğini unutmayın. Closure Compiler, kodda dize değişmezlerini asla değiştirmez. Bu nedenle, Closure Compiler, eval() ifadelerine iletilen dizeleri değiştirmez.

Bunların ilişkili ancak farklı sorunlar olduğunu unutmayın: derlenmişten hariciye iletişimi sürdürme ve hariciden derlenmişe iletişimi sürdürme. Bu ayrı sorunların ortak bir çözümü vardır ancak her iki tarafta da nüanslar bulunur. Closure Compiler'dan en iyi şekilde yararlanmak için hangi duruma sahip olduğunuzu anlamanız önemlidir.

Devam etmeden önce externs ve exports hakkında bilgi edinmeniz faydalı olabilir.

Derlenmiş koddan harici koda yapılan aramalarla ilgili çözüm: Extern'lerle derleme

Sayfanıza başka bir komut dosyası tarafından sağlanan kodu kullanıyorsanız Closure Compiler'ın, harici kitaplıkta tanımlanan sembollere yaptığınız referansların adını değiştirmediğinden emin olmanız gerekir. Bunun için, harici kitaplığın extern'lerini içeren bir dosyayı derlemenize ekleyin. Bu, Closure Compiler'a hangi adları kontrol etmediğinizi ve bu nedenle değiştirilemeyeceğini bildirir. Kodunuz, harici dosyanın kullandığı adları kullanmalıdır.

Bunun yaygın örnekleri arasında OpenSocial API ve Google Haritalar API'si gibi API'ler yer alır. Örneğin, kodunuz uygun harici dosyalar olmadan OpenSocial işlevi opensocial.newDataRequest()'yı çağırırsa Closure Compiler bu çağrıyı a.b()'ya dönüştürür.

Derlenmiş koddan harici koda yapılan çağrılarla ilgili çözüm: Externs'i uygulama

Kitaplık olarak yeniden kullandığınız JavaScript kodunuz varsa derlenmemiş kodun kitaplıktaki işlevleri çağırmasına izin verirken yalnızca kitaplığı küçültmek için Closure Compiler'ı kullanmak isteyebilirsiniz.

Bu durumda çözüm, kitaplığınızın herkese açık API'sini tanımlayan bir dizi harici değişken uygulamaktır. Kodunuz, bu harici dosyalarda tanımlanan semboller için tanımlar sağlar. Bu, stajyerlerinizin bahsettiği tüm sınıflar veya işlevler anlamına gelir. Bu, sınıflarınızın, externs'te belirtilen arayüzleri uygulaması anlamına da gelebilir.

Bu harici işlevler yalnızca sizin için değil, diğer kullanıcılar için de yararlıdır. Kitaplığınız, kullanıcıların bakış açısına göre harici bir komut dosyası olduğundan, kitaplığınızın tüketicileri kodlarını derlerken bu dosyaları eklemelidir. Harici kullanıcıları, sizinle tüketicileriniz arasındaki sözleşme olarak düşünün. Her ikinizin de bir kopyaya ihtiyacı var.

Bu nedenle, kodunuzu derlerken derlemeye extern'leri de eklediğinizden emin olun. Harici değişkenleri genellikle "başka bir yerden gelen" değişkenler olarak düşündüğümüz için bu durum alışılmadık görünebilir. Ancak Closure Compiler'a hangi sembolleri kullanıma sunduğunuzu söylemeniz gerekir. Böylece bu semboller yeniden adlandırılmaz.

Burada önemli bir uyarı, harici sembolleri tanımlayan kodla ilgili "yinelenen tanım" teşhisleri alabileceğinizdir. Closure Compiler, extern'lerdeki tüm sembollerin harici bir kitaplık tarafından sağlandığını varsayar ve şu anda tanımı kasıtlı olarak sağladığınızı anlayamaz. Bu teşhisler gizlenebilir ve gizleme işlemini, API'nizi gerçekten yerine getirdiğinizin onayı olarak düşünebilirsiniz.

Ayrıca Closure Compiler, tanımlarınızın harici bildirimlerin türleriyle eşleşip eşleşmediğini tür denetimiyle kontrol edebilir. Bu, tanımlarınızın doğru olduğuna dair ek onay sağlar.