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 azaltarak sayfa performansını nasıl iyileştirdiğini incelenmektedir.
Ölçüm
Optimizasyonlar eklemeye başlamadan önce, uygulamanın mevcut durumunu analiz etmek her zaman iyi bir fikirdir.
- Siteyi önizlemek için Uygulamayı Göster'e, ardından Tam Ekran'a basın.
"Kullanılmayan kodu kaldırma" codelab'inde de ele alınan bu uygulama, favori yavru kedinize oy vermenize olanak tanır. 🐈
Şimdi bu uygulamanın büyüklüğüne bir 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 seçin.
- Uygulamayı yeniden yükleyin.
Bu paket boyutunu küçültmek için "Kullanılmayan kodu kaldırın" codelab'inde büyük ilerleme kaydedilmiş olsa da 225 KB hâlâ oldukça büyük bir boyuttur.
Küçültme
Aşağıdaki kod bloğunu ele alalım.
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 elde edilen kod aşağıdaki gibi görünür:
function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}
Dosya boyutu şimdi yaklaşık 83 B olur. Değişken adının uzunluğu azaltılarak ve bazı ifadeler değiştirilerek daha da karışırsa son 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'ye ulaşır.
Her adımda, kodun okunması zorlaşmaktadır. Ancak, tarayıcının JavaScript motoru, bunların her birini tam olarak aynı şekilde yorumlar. Kodun bu şekilde kod karartması, dosya boyutunu küçültmenize yardımcı olabilir. 112 B başlangıç için pek fazla bir değer değildi, ancak boyutta bir %50 küçülme vardı!
Bu uygulamada webpack sürüm 4, modül paketleyici olarak kullanılır. Özel sürümü package.json
adresinde görebilirsiniz.
"devDependencies": {
//...
"webpack": "^4.16.4",
//...
}
Sürüm 4, üretim modunda varsayılan olarak paketi zaten küçültür. Terser için bir eklenti TerserWebpackPlugin
kullanır.
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üğü hakkında fikir edinmek için Geliştirici Araçları Ağ panelinden main.bundle.js
işaretini tıklayın. Şimdi Yanıt sekmesini tıklayın.
Kod, küçültülmüş ve karıştırılmış hâlde son haliyle yanıt gövdesinde gösterilir.
Paket küçültülmemiş olsaydı paketin ne kadar büyük olabileceğini öğrenmek için webpack.config.js
dosyasını açıp mode
yapılandırmasını güncelleyin.
module.exports = {
mode: 'production',
mode: 'none',
//...
Uygulamayı yeniden yükleyin ve DevTools Ağ panelinden paket boyutuna tekrar göz atın
Bu oldukça büyük bir fark. 😅
Devam etmeden önce burada yapılan değişiklikleri geri aldığınızdan emin olun.
module.exports = {
mode: 'production',
mode: 'none',
//...
Uygulamanızda kodu küçültme işleminin dahil edilmesi, kullandığınız araçlara bağlıdır:
- Webpack v4 veya sonraki sürümler kullanılıyorsa, üretim modunda kod varsayılan olarak küçültüldüğünden ek işlem yapılması gerekmez. 👍
- Webpack'in eski bir sürümü kullanılıyorsa
TerserWebpackPlugin
öğesini yükleyin ve web paketi derleme işlemine dahil edin. Belgelerde bu durum ayrıntılı olarak açıklanmaktadır. - Bunun yerine, BabelMinifyWebpackPlugin ve ClosureCompilerPlugin gibi başka küçültme eklentileri de mevcuttur ve kullanılabilir.
- Bir modül paketleyici hiç kullanılmıyorsa KSA aracı olarak Terser'ı kullanın veya doğrudan bağımlılık olarak ekleyin.
Sıkıştırma
Küçültme sürecinde kodun nasıl azaltıldığını açıklamak için bazen "sıkıştırma" terimi genel olarak kullanılsa da gerçekte 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. Tamamen geçerli bir kod sağlayan küçültmenin aksine, sıkıştırılmış kodun kullanılmadan önce sıkıştırması açılmalıdır.
Her HTTP isteği ve yanıtında tarayıcılar ve web sunucuları, getirilen veya alınan öğe hakkında ek bilgi eklemek için headers ekleyebilir. Bu, DevTools Network (Ağ) panelindeki Headers
sekmesinde üç tür gösterilir:
- Genel, istek-yanıt etkileşiminin tamamıyla alakalı genel üstbilgileri temsil eder.
- Yanıt Başlıkları, sunucudan gelen gerçek yanıta özgü başlıkların bir listesini gösterir.
- İstek Başlıkları, istemci tarafından yapılan isteğe ekli başlıkların bir listesini gösterir.
Request Headers
etiketindeki accept-encoding
başlığına göz atın.
accept-encoding
, tarayıcı tarafından hangi içerik kodlama biçimlerini veya sıkıştırma algoritmalarını desteklediğ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ırmasının açılması) için burada desteklenen yalnızca üç algoritma vardır:
- Gzip (
gzip
): Sunucu ve istemci etkileşimleri için en yaygın kullanılan sıkıştırma biçimi. Deflate algoritmasını temel alır ve mevcut tüm tarayıcılarda desteklenir. - Söndür (
deflate
): Yaygın olarak kullanılmaz. - Brotli (
br
): Sıkıştırma oranlarını daha da iyileştirerek sayfaların daha da hızlı yüklenmesini sağlamayı amaçlayan yeni bir sıkıştırma algoritması. Çoğu tarayıcının en son sürümlerinde desteklenir.
Bu eğitimdeki örnek uygulama, Express'in 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 incelenecektir.
Dinamik sıkıştırma
Dinamik sıkıştırma, tarayıcı tarafından istenilen öğelerin o anda 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şlemlerinin yapılması gerekmez.
- 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ı öğelerin sunucu tarafından gönderilmeden önce sıkıştırılmasını beklerken bir performans isabetine neden olabilir.
Düğüm/Ekspres ile dinamik sıkıştırma
server.js
dosyası, uygulamayı barındıran Düğüm sunucusunu kurmaktan 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 tüm bu işlem, express
dosyasını içe aktarmak ve public/
dizinindeki tüm statik HTML, JS ve CSS dosyalarını yüklemek için express.static
ara katman yazılımını kullanmaktır (ve 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 katman yazılımı kitaplığı kullanılabilir. package.json
alanına devDependency
olarak ekleyerek başlayın:
"devDependencies": {
//...
"compression": "^1.7.3"
},
Ve bu değeri sunucu dosyasına (server.js
) aktarın:
const express = require('express');
const compression = require('compression');
Ayrıca, express.static
eklenmeden önce bunu bir ara katman yazılımı olarak ekleyin:
//...
const app = express();
app.use(compression());
app.use(express.static('public'));
//...
Şimdi uygulamayı yeniden yükleyin ve Ağ panelindeki paket boyutuna göz atın.
225 KB'tan 61,6 KB'a! Şimdi Response Headers
içindeki content-encoding
üst bilgisi, sunucunun bu dosyayı gzip
ile kodlanmış olarak gönderdiğini gösterir.
Statik sıkıştırma
Statik sıkıştırmanın amacı, öğelerin önceden sıkıştırılarak zamandan tasarruf edilmesini sağlamaktır.
Artıları
- Yüksek sıkıştırma seviyelerinden kaynaklanan gecikme artık sorun değil. Sıkıştırma işlemi sırasında dosyalar doğrudan alınabileceğinden, anında sıkıştırılması gerekmez.
Eksileri
- Öğelerin her derlemede sıkıştırılması gerekir. Yüksek sıkıştırma seviyeleri kullanılırsa 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ı gerektirdiğinden web paketi ayarları, derleme adımının bir parçası olarak öğeleri sıkıştıracak şekilde değiştirilebilir.
Bunun için CompressionPlugin
kullanılabilir.
package.json
alanına devDependency
olarak ekleyerek başlayın:
"devDependencies": {
//...
"compression-webpack-plugin": "^1.1.11"
},
Diğer tüm web paketi eklentileri gibi, bu eklenti de yapılandırma dosyasına
webpack.config.js:
içe aktarın.
const path = require("path");
//...
const CompressionPlugin = require("compression-webpack-plugin");
Ve bunu plugins
dizisine ekleyin:
module.exports = {
//...
plugins: [
//...
new CompressionPlugin()
]
}
Varsayılan olarak eklenti, derleme dosyalarını gzip
kullanarak sıkıştırır. Farklı bir algoritma kullanmak veya belirli dosyaları dahil etmek/hariç tutmak amacıyla nasıl seçenek ekleyeceğinizi öğrenmek için belgelere göz atın.
Uygulama yeniden yüklenip yeniden oluşturulduğunda ana paketin sıkıştırılmış bir sürümü oluşturulur. Düğüm sunucusu tarafından sunulan son public/
dizininde ne olduğuna bakmak 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'lenmiş sürümü olan main.bundle.js.gz
artık buraya da kaydedildi. CompressionPlugin
ayrıca varsayılan olarak index.html
sıkıştırır.
Yapılması gereken bir sonraki şey, sunucuya orijinal JS sürümleri istendiğinde bu gzip biçiminde sıkıştırılmış dosyaları göndermesini söylemektir. Bu işlem, dosyalar express.static
ile sunulmadan önce server.js
içinde yeni bir rota tanımlanarak yapılabilir.
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 bildirmek için kullanılır. Daha sonra, 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'
belirtilmesi, bunun bir JS dosyası getirmek üzere tetiklenen her uç nokta için kullanılacağı anlamına gelir. - Geri çağırmaya
.gz
, isteğin URL'sine eklenmiş veContent-Encoding
yanıt başlığıgzip
olarak ayarlanmıştır. - Son olarak
next()
, sıranın bir sonraki geri çağırmaya devam etmesini sağlar.
Uygulama yeniden yüklendikten sonra Network
paneline bir kez daha bakın.
Daha önce olduğu gibi, paket boyutunda önemli bir küçülme!
Sonuç
Bu codelab'de, kaynak kodu küçültme ve sıkıştırma süreci ele alınmıştır. Bu tekniklerin her ikisi de günümüzde kullanılan araçların çoğunda varsayılan haline gelmektedir. Bu nedenle araç zincirinizin bunları zaten destekleyip desteklemediğini veya her iki süreci de kendiniz uygulamaya başlamanız gerekip gerekmediğini öğrenmek önemlidir.