Bu codelab'de, aşağıdaki uygulama için JavaScript paketinin hem küçültülmesinin hem de sıkıştırılmasının, uygulamanın istek boyutunu küçülterek sayfa performansını nasıl artırdığı ele alınmaktadır.
Ölçüm
Optimizasyon eklemeye başlamadan önce uygulamanın mevcut durumunu analiz etmek her zaman iyi bir fikirdir.
- Siteyi önizlemek için Uygulamayı Görüntüle'ye basın. Ardından Tam Ekran'a basın.
"Kullanılmayan kodu kaldırma" adlı codelab'de de ele alınan bu uygulama, en sevdiğiniz yavru kediye oy vermenizi sağlar. 🐈
Şimdi bu uygulamanın ne kadar büyük olduğuna bakın:
- Geliştirici Araçları'nı açmak için `Control+Shift+J` (veya Mac'te `Command+Option+J`) tuşlarına basın.
- Ağ sekmesini tıklayın.
- Önbelleği devre dışı bırak onay kutusunu işaretleyin.
- Uygulamayı yeniden yükleyin.
Bu paket boyutunu küçültmek için "Kullanılmayan kodu kaldırma" codelab'inde önemli ölçüde ilerleme kaydedilmiş olsa da 225 KB hâlâ oldukça büyük bir boyut.
Sadeleştirme
Aşağıdaki kod bloğunu inceleyin.
function soNice() {
let counter = 0;
while (counter < 100) {
console.log('nice');
counter++;
}
}
Bu işlev kendi dosyasına kaydedilirse dosya boyutu yaklaşık 112 B (bayt) olur.
Tüm boşluklar kaldırılırsa ortaya çıkan kod şu şekilde görünür:
function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}
Dosya boyutu yaklaşık 83 B olur. Değişken adının uzunluğu azaltılıp bazı ifadeler değiştirilerek daha da bozulursa nihai kod aşağıdaki gibi görünebilir:
function soNice(){for(let i=0;i<100;)console.log("nice"),i++}
Dosya boyutu artık 62 B'a ulaşıyor.
Her adımda kodun okunması zorlaşıyor. Ancak tarayıcının JavaScript motoru, bunların her birini aynı şekilde yorumlar. Bu şekilde kodu karartmanın avantajı, daha küçük dosya boyutları elde etmeye yardımcı olabilir. 112 B zaten çok büyük bir boyut değildi ancak yine de %50 oranında küçülme oldu.
Bu uygulamada, modül paketleyici olarak webpack sürüm 4 kullanılır. Belirli sürümü package.json
adresinde görebilirsiniz.
"devDependencies": {
//...
"webpack": "^4.16.4",
//...
}
4. sürüm, üretim modunda paketi varsayılan olarak zaten küçültür. TerserWebpackPlugin
Terser için bir eklenti kullanıyorsanız
Terser, JavaScript kodunu sıkıştırmak için kullanılan popüler bir araçtır.
Küçültülmüş kodun nasıl göründüğüne dair fikir edinmek için Geliştirme Araçları Ağ panelindeyken main.bundle.js
simgesini tıklayın. Şimdi Yanıt sekmesini tıklayın.
Son biçimindeki, küçültülmüş ve bozulmuş kod, yanıt gövdesinde gösterilir.
Paketin küçültülmemiş olması durumunda ne kadar büyük olabileceğini öğrenmek için webpack.config.js
dosyasını açın ve mode
yapılandırmasını güncelleyin.
module.exports = {
mode: 'production',
mode: 'none',
//...
Uygulamayı yeniden yükleyin ve Geliştirici Araçları Ağ paneli üzerinden paket boyutuna tekrar göz atın.
Bu oldukça büyük bir fark. 😅
Devam etmeden önce buradaki değişiklikleri geri aldığınızdan emin olun.
module.exports = {
mode: 'production',
mode: 'none',
//...
Uygulamanızda kodu küçültme işlemini dahil etme, kullandığınız araçlara bağlıdır:
- webpack v4 veya daha yeni bir sürüm kullanılıyorsa üretim modunda kod varsayılan olarak küçültüldüğünden ek bir işlem yapılması gerekmez. 👍
- webpack'in eski bir sürümü kullanılıyorsa
TerserWebpackPlugin
öğesini yükleyip webpack derleme işlemine dahil edin. Bu konu, dokümanlarda ayrıntılı olarak açıklanmaktadır. - BabelMinifyWebpackPlugin ve ClosureCompilerPlugin gibi başka küçültme eklentileri de vardır ve bunlar da kullanılabilir.
- Hiçbir modül paketleyici kullanılmıyorsa Terser'i bir CLI aracı olarak kullanın veya doğrudan bağımlılık olarak ekleyin.
Sıkıştırma
"Sıkıştırma" terimi bazen küçültme işlemi sırasında kodun nasıl azaltıldığını açıklamak için gevşek bir şekilde kullanılsa da aslında kelimenin tam anlamıyla sıkıştırılmaz.
Sıkıştırma genellikle bir veri sıkıştırma algoritması kullanılarak değiştirilmiş kodu ifade eder. Mükemmel şekilde geçerli kod sağlayan küçültme işleminin aksine, sıkıştırılmış kodun kullanılmadan önce açılması gerekir.
Tarayıcılar ve web sunucuları, her HTTP isteği ve yanıtında üst bilgiler ekleyerek getirilen veya alınan öğe hakkında ek bilgiler sağlayabilir. Bu durum, Geliştirici Araçları Ağ panelindeki Headers
sekmesinde görülebilir. Burada üç tür gösterilir:
- Genel, tüm istek-yanıt etkileşimiyle alakalı genel üstbilgileri ifade eder.
- Yanıt Başlıkları, sunucudan gelen gerçek yanıta özel başlıkların listesini gösterir.
- İstek Başlıkları, istemci tarafından isteğe eklenen başlıkların listesini gösterir.
Request Headers
bölümündeki accept-encoding
başlığına göz atın.
accept-encoding
, tarayıcı tarafından hangi içerik kodlama biçimlerinin veya sıkıştırma algoritmalarının desteklendiğini belirtmek için kullanılır. Piyasada birçok metin sıkıştırma algoritması vardır ancak HTTP ağ isteklerinin sıkıştırılması (ve sıkıştırmanın açılması) için burada yalnızca üç algoritma desteklenir:
- Gzip (
gzip
): Sunucu ve istemci etkileşimlerinde en yaygın kullanılan sıkıştırma biçimidir. Deflate algoritması üzerine kurulmuştur ve mevcut tüm tarayıcılarda desteklenir. - Sıkıştırma (
deflate
): Yaygın olarak kullanılmaz. - Brotli (
br
): Sıkıştırma oranlarını daha da iyileştirmeyi amaçlayan yeni bir sıkıştırma algoritmasıdır. Bu algoritma, sayfa yüklemelerinin daha da hızlı olmasını sağlayabilir. Çoğu tarayıcının en yeni sürümlerinde desteklenir.
Bu eğitimdeki örnek uygulama, Express artık sunucu çerçevesi olarak kullanılması dışında, "Kullanılmayan kodu kaldırma" codelab'inde tamamlanan uygulamayla aynıdır. Sonraki birkaç bölümde hem statik hem de dinamik sıkıştırma ele alınmaktadır.
Dinamik sıkıştırma
Dinamik sıkıştırma, öğeler tarayıcı tarafından istendikçe anında sıkıştırılmasını içerir.
Artıları
- Öğelerin kaydedilmiş sıkıştırılmış sürümlerini oluşturma ve güncelleme işlemi yapılmaz.
- Anında sıkıştırma, özellikle dinamik olarak oluşturulan web sayfalarında iyi sonuç verir.
Eksileri
- Daha iyi sıkıştırma oranları elde etmek için dosyaları daha yüksek düzeylerde sıkıştırmak daha uzun sürer. Bu durum, kullanıcı sunucu tarafından gönderilmeden önce öğelerin sıkıştırılmasını beklediği için performansın düşmesine neden olabilir.
Node/Express ile dinamik sıkıştırma
server.js
dosyası, uygulamayı barındıran Node sunucusunu ayarlamaktan sorumludur.
const express = require('express');
const app = express();
app.use(express.static('public'));
const listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
Şu anda bu işlem yalnızca express
öğesini içe aktarıp express.static
ara yazılımını kullanarak public/
dizinindeki tüm statik HTML, JS ve CSS dosyalarını yükler (bu dosyalar her derlemede webpack tarafından oluşturulur).
Tüm öğelerin her istendiğinde sıkıştırıldığından emin olmak için sıkıştırma ara yazılım kitaplığı kullanılabilir. Öncelikle package.json
listesine devDependency
olarak ekleyin:
"devDependencies": {
//...
"compression": "^1.7.3"
},
Ardından, server.js
sunucu dosyasına aktarın:
const express = require('express');
const compression = require('compression');
Ayrıca, express.static
monte edilmeden önce ara katman yazılımı olarak ekleyin:
//...
const app = express();
app.use(compression());
app.use(express.static('public'));
//...
Şimdi uygulamayı yeniden yükleyin ve Network panelindeki paket boyutuna göz atın.
225 KB'tan 61,6 KB'a! Response Headers
bölümünde, content-encoding
başlığı, sunucunun bu dosyayı gzip
ile kodlanmış olarak gönderdiğini gösteriyor.
Statik sıkıştırma
Statik sıkıştırmanın temelinde, öğelerin önceden sıkıştırılıp kaydedilmesi fikri yatar.
Artıları
- Yüksek sıkıştırma seviyelerinden kaynaklanan gecikme artık sorun değil. Artık dosyalar doğrudan getirilebildiğinden, sıkıştırmak için anında işlem yapılması gerekmez.
Eksileri
- Öğelerin her derlemede sıkıştırılması gerekir. Yüksek sıkıştırma seviyeleri kullanıldığında derleme süreleri önemli ölçüde artabilir.
Node/Express ve webpack ile statik sıkıştırma
Statik sıkıştırma, dosyaların önceden sıkıştırılmasını içerdiğinden webpack ayarları, derleme adımının bir parçası olarak öğeleri sıkıştıracak şekilde değiştirilebilir.
CompressionPlugin
bu amaçla kullanılabilir.
Öncelikle package.json
listesine devDependency
olarak ekleyin:
"devDependencies": {
//...
"compression-webpack-plugin": "^1.1.11"
},
Diğer tüm webpack eklentileri gibi, yapılandırma dosyasına aktarın,
webpack.config.js:
const path = require("path");
//...
const CompressionPlugin = require("compression-webpack-plugin");
Aşağıdaki plugins
dizisine ekleyin:
module.exports = {
//...
plugins: [
//...
new CompressionPlugin()
]
}
Eklenti, varsayılan olarak derleme dosyalarını gzip
kullanarak sıkıştırır. Farklı bir algoritma kullanmak veya belirli dosyaları dahil etmek/hariç tutmak için seçenekleri nasıl ekleyeceğinizi öğrenmek üzere belgelere göz atın.
Uygulama yeniden yüklendiğinde ve yeniden oluşturulduğunda ana paketin sıkıştırılmış bir sürümü oluşturulur. Node sunucusu tarafından sunulan son public/
dizininin içeriğine göz atmak için Glitch Console'u açın.
- Araçlar düğmesini tıklayın.
- Konsol düğmesini tıklayın.
- Konsolda,
public
dizinine geçmek ve tüm dosyalarını görmek için aşağıdaki komutları çalıştırın:
cd public
ls
Paketin gzip ile sıkıştırılmış sürümü, main.bundle.js.gz
, artık buraya da kaydediliyor. CompressionPlugin
, varsayılan olarak index.html
öğesini de sıkıştırır.
Yapılması gereken bir sonraki işlem, sunucuya orijinal JS sürümleri istendiğinde bu gzip'li dosyaları göndermesini söylemektir. Bu işlem, dosyalar server.js
ile sunulmadan önce server.js
içinde yeni bir rota tanımlanarak yapılabilir.express.static
const express = require('express'); const app = express(); app.get('*.js', (req, res, next) => { req.url = req.url + '.gz'; res.set('Content-Encoding', 'gzip'); next(); }); app.use(express.static('public')); //...
app.get
, sunucuya belirli bir uç nokta için GET isteğine nasıl yanıt vereceğini söylemek için kullanılır. Ardından, bu isteğin nasıl işleneceğini tanımlamak için bir geri çağırma işlevi kullanılır. Rota şu şekilde çalışır:
- İlk bağımsız değişken olarak
'*.js'
belirtmek, bir JS dosyası getirmek için tetiklenen her uç nokta için geçerli olduğu anlamına gelir. - Geri çağırmada,
.gz
isteğin URL'sine eklenir veContent-Encoding
yanıt başlığıgzip
olarak ayarlanır. - Son olarak,
next()
, sıranın bir sonraki geri çağırmayla devam etmesini sağlar.
Uygulama yeniden yüklendikten sonra Network
paneline tekrar göz atın.
Tıpkı daha önce olduğu gibi, paket boyutunda önemli bir azalma elde ettik.
Sonuç
Bu kod laboratuvarında, kaynak kodunu küçültme ve sıkıştırma süreci ele alındı. Bu tekniklerin her ikisi de günümüzde mevcut olan birçok araçta varsayılan olarak kullanılmaya başlandı. Bu nedenle, araç zincirinizin bu teknikleri destekleyip desteklemediğini veya her iki süreci de kendiniz uygulamaya başlayıp başlamayacağınızı öğrenmeniz önemlidir.