Ana içeriğe geç

JavaScript Minify Nedir? Terser.js ile Kod Optimizasyonu

JavaScript Minify Nedir? Terser.js ile Kod Optimizasyonu - Web Geliştirme Rehberi

Bir noktaya kadar UglifyJS, JavaScript küçültme işleminin tartışmasız standardıydı. Ama modern sözdizimi yaygınlaşınca bir sorun ortaya çıktı: UglifyJS'in aktif kolunun ES6 kodu işleyememesi. Arrow function, destructuring, template literal içeren bir dosyayı UglifyJS'e verdiğinizde genellikle parse hatası alıyordunuz. Bu boşluğu doldurmak için geliştirilen Terser, bugün fiili standart hâline geldi.

Terser, UglifyES'in 2018'de terk edilmesinin ardından onun fork'u olarak başladı ve aktif geliştirmeyi sürdürdü. Webpack 5, Vite ve Rollup; üçü de ya Terser'i varsayılan küçültme aracı olarak kullanır ya da birinci tercih olarak sunar. Bu yaygınlık tesadüf değil: ES6+'ı düzgün işlemek, source map desteği ve esnek yapılandırma seçenekleri bu konumun temel nedenleri.

Compress ve mangle: iki ayrı işlem

JavaScript minify tek bir adımdan ibaret değildir. Arka planda iki farklı dönüşüm katmanı çalışır ve bunları birbirinden ayırt etmek, ayarları neden yaptığınızı anlamanızı sağlar.

İlk katman compress'tir. Bu aşamada kod mantıksal olarak sadeleştirilir:

  • Sabit ifadeler derleme zamanında hesaplanır: 60 * 60 * 24 ifadesi 86400'e dönüşür.
  • Erişilemeyen kod silinir. Bir return ifadesinden sonra gelen satırlar üretim çıktısına dahil edilmez.
  • Koşullar sadeleştirilir. if (true) { ... } else { ... } yapısında else bloğu atılır.
  • Kullanılmayan değişkenler ve fonksiyonlar tespit edilerek kaldırılır.

İkinci katman mangle'dır. Compress kodun mantığını sadeleştirirken, mangle sembol adlarını kısaltır. userAuthenticationStatus gibi uzun bir değişken adı a ya da b'ye indirgenebilir. İç içe geçmiş fonksiyonlarda ve büyük modüllerde bu kazanım hızla büyür çünkü string olarak saklanan sembol adları dosyada fiziksel yer kaplar.

Her ikisi birlikte uygulandığında çıktı, gzip veya Brotli sıkıştırmasıyla birleşince kayda değer bir transfer boyutu azalması sağlar. Compress mantıksal yükü azaltır; mangle sözcüksel yükü. İkisi bağımsız kapatılabildiği için belirli durumlarda yalnızca biri devreye alınabilir; örneğin mangle'ı devre dışı bırakıp yalnızca compress çalıştırmak hem boyut kazancı hem de okunabilir hata izleri sağlar.

İki katman. Birbirinden bağımsız.

Kurulum ve temel kullanım

Kurulum standart bir geliştirici bağımlılığı olarak yapılır:

npm install terser --save-dev

CLI üzerinden tek dosyayı küçültmek için:

terser input.js -o output.min.js --compress --mangle

Source map üretmek için --source-map bayrağını ekleyin:

terser input.js -o output.min.js --source-map "url='output.min.js.map'" --compress --mangle

Birden fazla dosyayı veya özelleştirilmiş seçenekleri işlemek gerektiğinde Node.js API daha kullanışlıdır:

import { minify } from 'terser';

const result = await minify(code, {
  compress: {
    drop_console: true,
    passes: 2
  },
  mangle: {
    toplevel: false
  },
  format: {
    comments: false
  }
});

console.log(result.code);

API yolunu tercih etmenin pratik bir avantajı var: ayarlar versiyon kontrolü altında kalır ve ortama göre koşullu yapılandırma kolaylaşır. Development ortamında mangle'ı kapatıp production'da açmak veya staging ortamı için console.log'ları korumak bu şekilde daha temiz yönetilir.

Ayar kararları: ne zaman dikkat gerekir

Terser'in varsayılanları çoğu proje için makul başlangıç noktası sunar. Ancak bazı seçenekler dikkat gerektiren trade-off'lar taşır.

compress.drop_console — Tüm console.* çağrılarını siler. Sorun şurada çıkar: kasıtlı bırakılmış uyarılar, deprecation mesajları veya kullanıcıya görünmesi tasarlanmış loglar da bu seçenekle ortadan kalkar. Kaldırılması gereken loglar kaynak kodda temizlenirse bu seçeneğe hiç gerek kalmaz; daha güvenli bir yaklaşımdır.

compress.passes — Sıkıştırma kaç kez uygulanır. İki geçiş, tek geçişte temizlenemeyen ifadeleri ikincide yakalayabilir; küçük ama gerçek bir boyut farkı üretir. Bununla birlikte derleme süresi artar. Büyük projelerde bu ek süre CI pipeline'ında görünür hâle gelir. Çoğu uygulama için passes: 1 yeterlidir.

mangle.toplevel — Modül sınırlarının dışına açık olan isimleri de kısaltır. Bir uygulama geliştiriyorsanız ve dışa aktarılan isimlere sadece kendi kodunuz erişiyorsa bu seçenek faydalıdır. Kütüphane geliştiriyorsanız, dışa aktarılan fonksiyon ve sınıf adları bozulacağından kesinlikle kapalı kalmalıdır.

Mangle'ın nerede bittiği, obfuscation'ın nerede başladığı sıkça karıştırılır. Bu üç yöntemi karşılaştıran yazı bu sınırı somut örneklerle çiziyor.

Kütüphane kodu için mangle.reserved boş bırakılmamalıdır. Runtime'da string ile erişilen özellik adları, üçüncü taraf scriptlerin beklediği global değişkenler veya özel event isimleri bu listeye girebilir — bunların kısaltılması sessiz çalışma hatalarına yol açar.

Lisans yorumu barındıran kütüphanelerde format.comments: false yasal yükümlülük yaratabilir. 'some' değeri veya özel bir regex ile yalnızca lisans satırı korunabilir; geri kalan tüm yorumlar temizlenir.

Agresif ayarların paylaştığı bir risk var: üretimde beklenmedik bir hata çıktığında mangle derinleştikçe yığın izleri anlamsız hâle gelir. a adlı bir değişkeni kaynak kodda aramak mümkün değildir. Mangle ayarlarını sıkıştırdığınızda source map üretimi neredeyse zorunludur; dosyayı kamuya açmadan sunucuda saklayabilir, yalnızca hata izleme servisinizin erişimine açabilirsiniz. Küçültülmüş çıktıyı geri okumak gerektiğinde beautify sürecini ele alan yazı bu aşamayı ayrıca inceliyor.

Source map olmadan mangle anlamsız hâle gelir.

Webpack, Vite ve Rollup entegrasyonu

CLI doğrudan çalıştırmak küçük ve bağımsız projeler için yeterlidir. Bir paketleyici zaten devredeyse entegrasyon o katmanda yapılır.

Webpack, sürüm 5'ten itibaren TerserPlugin'i mode: 'production' ayarında otomatik devreye alır. Seçenekleri özelleştirmek için:

const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: { drop_console: true },
          mangle: { toplevel: false }
        }
      })
    ]
  }
};

Vite, production build'de varsayılan olarak esbuild kullanır; esbuild daha hızlı derler ancak Terser'e kıyasla daha büyük çıktı verir. Terser'e geçmek için:

// vite.config.js
export default {
  build: {
    minify: 'terser',
    terserOptions: {
      compress: { passes: 2 }
    }
  }
};

Prototip veya iç araç geliştiriyorsanız esbuild hızı muhtemelen daha değerlidir. Uzun ömürlü, yüksek trafikli bir uygulama için Terser'in çıktı kalitesi farkı anlamlı olabilir.

Rollup için @rollup/plugin-terser paketi kullanılır:

import terser from '@rollup/plugin-terser';

export default {
  plugins: [terser()]
};

Her üç araçta da seçenekler aynı Terser API'sine iletilir; dolayısıyla öğrendiğiniz ayar mantığı aracı değiştirseniz de geçerliliğini korur.

Hedef ortam ve sözdizimi uyumluluğu

Babel ve Terser aynı pipeline'da çalışırken ecma değerleri tutarsız bırakılırsa çıktı tahmin edilemez hâle gelir. Babel ES5'e indirdiği kodu Terser ecma: 2020 ile işlerse bazı yapıları geri modernize etmeye çalışır. Her iki araçta hedef sürümü eşitleyin; tek bir yapılandırma dosyasında tutmak bu tutarsızlığı önler.

Terser hangi sözdizimini hedeflediğinizi compress.ecma ve format.ecma seçenekleriyle belirler. ecma: 2020 değeri verildiğinde arrow function ve nullish coalescing gibi modern yapılar çıktıda korunabilir; bazı durumlarda daha uzun sözdizimi modern kısa eşdeğerine dönüştürülür. Eski tarayıcılara ES5 çıktısı üretmek istiyorsanız bu dönüşümü Babel üstlenir; Terser bu Babel çıktısını alıp küçültür. Terser sözdizimini modernize etmez, küçültür.

Minify sonrası iki şeyi doğrulamak gerekir: boyut ve davranış. Boyut için gzip edilmiş çıktıya bakın; ham .min.js boyutu yanıltıcı olabilir çünkü tarayıcıya ulaşan sıkıştırılmış sürümdür. Sayfa ağırlığını ve yük sürelerini ölçmek için Site Hız Testi aracı transfer boyutlarını görsel olarak karşılaştırma imkânı sunar. Davranış açısından özellikle toplevel: true veya passes: 2 kullandıysanız dışa aktarılan fonksiyonların hâlâ erişilebilir olduğunu fonksiyonel testlerle doğrulayın. Üretimde tanımlaması güç hatalar çoğunlukla mangle kararlarından kaynaklanır.

JavaScript dosyalarınızı küçültmek için aracı doğrudan kullanabilirsiniz.