Google Closure Compiler: Mirası, Dersler ve Modern Alternatifler
Google'ın 2009'da çıkardığı Closure Compiler'ın modern web araçlarını nasıl şekillendirdiğini ve bugünkü build araçlarına kalıcı etkisini inceliyoruz.
Google’ın Closure Compiler’ı 2009’da JavaScript’e tüm program kapsamında statik analizi getirdi: dosyalar arası dead code elimination ve JSDoc tabanlı type checking. Bu, webpack, esbuild ya da TypeScript bu yetenekleri yaygınlaştırmadan yıllar önceydi. Bu kökenin farkında olmayan ekipler aynı fikirleri sık sık yeniden keşfediyor ve yeni araçlara atfediyor.
2009’da Tüm Program Kapsamında Analiz#
Gelişmiş Dead Code Elimination#
Closure Compiler fonksiyon çağrılarını tüm codebase’iniz boyunca takip ediyor, hiçbir yerden referans verilmeyen kodu tamamen kaldırıyordu. Dönemin diğer araçları boşluk kaldırmak ve değişken yeniden adlandırmakla yetiniyordu:
// Closure Compiler öncesi
function calculateTax(amount, rate) {
return amount * rate;
}
function formatCurrency(amount) {
return '$' + amount.toFixed(2);
}
function processOrder(order) {
const tax = calculateTax(order.amount, 0.08);
return order.amount + tax; // formatCurrency hiç çağrılmıyor!
}
// Advanced compilation sonrası
function a(b){return 1.08*b.amount}
Compiler, formatCurrency fonksiyonunu hiç çağrılmadığını ispatlayabildiği için tamamen kaldırırdı.
TypeScript’ten Önce Type Checking#
Closure Compiler ayrıca JSDoc annotation’ları ile ifade edilen bir type sistemi sunuyordu:
/**
* @param {number} width
* @param {number} height
* @return {number}
*/
function calculateArea(width, height) {
return width * height;
}
/**
* @param {string} name
* @param {!Array<number>} scores
*/
function processStudent(name, scores) {
// Compiler burada type uyumsuzluklarını yakalar
const area = calculateArea(name, scores); // Hata!
}
Closure Library Mimarisi#
Closure Library, Google’ın karmaşık web uygulamaları geliştirme sorununun cevabıydı. Bugün oldukça modern görünen component-based bir mimari sağlıyordu:
// Closure Library component pattern'i (2010 civarı)
goog.provide('myapp.UserProfile');
goog.require('goog.ui.Component');
goog.require('goog.dom');
/**
* @constructor
* @extends {goog.ui.Component}
*/
myapp.UserProfile = function() {
goog.ui.Component.call(this);
};
goog.inherits(myapp.UserProfile, goog.ui.Component);
myapp.UserProfile.prototype.createDom = function() {
this.setElementInternal(
goog.dom.createDom('div', 'user-profile')
);
};
Bu dependency management sistemi (goog.provide ve goog.require) aslında erken bir modül sistemiydi ve hem AMD’nin hem de CommonJS’in yaygınlaşmasından önce geliyordu. Compiler bu modül yapısını kullanarak tüm codebase’i analiz ediyor, dosya sınırlarını aşarak erişilemeyen kodu atıyordu: bugünkü tree shaking’in atası.
Performans Kazanımı Nereden Geliyordu#
Kazanç birkaç somut mekanizmadan geliyordu. ADVANCED modu, dahili olduğunu ispatlayabildiği her property ve değişkeni yeniden adlandırıyor, küçük fonksiyonları inline ediyor ve çağrı grafiğinin hiç ulaşmadığı dalları siliyordu. jQuery döneminin codebase’lerinde taşınan ağırlığın büyük kısmı kimsenin çağırmadığı kütüphane yüzeyiydi; bu kombinasyon bundle’ın önemli bir bölümünü kesiyordu. İkinci kazanç compile-time type checking’di: uyumsuzluklar tarayıcıya ulaşmadan, build sırasında ortaya çıkıyordu.
Yine de migration sancılıydı. Öğrenme eğrisi dikti, optimize edilmiş çıktıyı debug etmek daha da zordu. Production’da bir şeyler ters gittiğinde şöyle hatalar görürdünüz:
TypeError: Cannot read property 'a' of undefined at b.c (compiled.js:1:23847)
Source map’ler o dönemde henüz erken geliştirme aşamasındaydı ve production hatalarını orijinal kodla ilişkilendirmek zordu. Bu debugging zorluğu, Closure’ın benimsenmesini ciddi şekilde engelledi.
Closure Araçlarının Düşüşü#
Araçlar çevresindeki her şeyin teknik olarak önündeydi ve yine de mindshare kaybettiler.
Developer Experience Açığı#
Araçlar güçlü olsa da önemli bir mindset değişimi gerektiriyordu. JSDoc annotation’larının verbosity’si, o dönemde popüler olan loose, dynamic JavaScript’e kıyasla ağır geliyordu:
// Developer'ların yazmak istediği
function add(a, b) {
return a + b;
}
// Closure'ın optimizasyon için gerektirdiği
/**
* @param {number} a
* @param {number} b
* @return {number}
*/
function add(a, b) {
return a + b;
}
Ekosistemin Parçalanması#
JavaScript ekosistemi CommonJS’e ve daha sonra ES modüllerine doğru ilerliyordu. Closure’ın goog.provide/goog.require sistemi giderek izole kalıyordu:
Build Kurulumunun Karmaşıklığı#
Closure Compiler’ı kurmak kolay değildi. Tipik bir build konfigürasyonu şöyle görünürdü:
// closure-build.js (basitleştirilmiş versiyon)
const compiler = require('google-closure-compiler').compiler;
new compiler({
js: 'src/**.js',
compilation_level: 'ADVANCED_OPTIMIZATIONS',
externs: 'externs/jquery.js',
warning_level: 'VERBOSE',
jscomp_error: 'checkTypes',
output_wrapper: '(function(){%output%})();'
});
Bunu, “zero configuration” modunu getiren webpack 4 ile karşılaştırın.
Araçlardan Uzun Yaşayan Fikirler#
Her modern bundler’ın öne çıkardığı tree shaking, Closure Compiler’ın öncülük ettiği dead code elimination’ın ta kendisi:
// Modern tree shaking (webpack/rollup)
import { debounce } from 'lodash'; // Sadece debounce'u import eder
Terser ve esbuild aynı optimizasyon tekniklerinin çoğunu daha iyi bir developer experience ile uyguluyor. TypeScript’in popülaritesi de developer’ların JavaScript’te type safety istediğini kanıtladı; annotation’ları, Closure’ın JSDoc ile ifade ettiği fikri taşıyor:
// TypeScript (modern)
function calculateArea(width: number, height: number): number {
return width * height;
}
// vs Closure JSDoc (2009)
/**
* @param {number} width
* @param {number} height
* @return {number}
*/
function calculateArea(width, height) {
return width * height;
}
Closure Araçları Bugün#
Yeni bir projede Closure araçları nadiren doğru seçim. Ekosistem ilerlemiş durumda ve modern alternatifler çoğu use case için daha iyi developer experience sağlıyor. Google, Closure Library deposunu 2024’te arşivledi; Closure Compiler’ın bakımı ise devam ediyor.
Zaten Closure araçları kullanan bir proje üzerinde çalışıyorsanız migration için acele etmeyin. Google’ın birçok ürünü bunları yıllarca başarıyla kullandı. Araçlar kararlı ve takımınız onları iyi biliyorsa sırf araç tercihi migration maliyetini haklı çıkarmaz.
Öğrenme amaçlı, compiler’ın kaynak kodu statik analiz ve optimizasyon teknikleri için hala okumaya değer.
Kaynaklar#
- Closure Compiler - Google for Developers (yeni sekmede açılır) - Derleme seviyeleri, tür açıklamaları ve dışsal tanımlar hakkında dokümantasyon içeren resmi Google Closure Compiler ana sayfası
- Closure Compiler Dokümantasyonu - Başlarken (yeni sekmede açılır) - WHITESPACE_ONLY, SIMPLE ve ADVANCED derleme modlarıyla Closure Compiler uygulamasını kullanmaya adım adım kılavuz
- google/closure-compiler - GitHub (yeni sekmede açılır) - Bayraklar, tür açıklama sözdizimi ve JS modül desteğini kapsayan wiki ile birlikte resmi kaynak deposu
- Closure Compiler - JavaScript Açıklamaları (yeni sekmede açılır) - ADVANCED derleme modu için gereken JSDoc tabanlı tür açıklamalarına yönelik wiki referansı
- esbuild - Web için Son Derece Hızlı Paketleyici (yeni sekmede açılır) - Benzer optimizasyon hedeflerine çok daha basit bir API ile ulaşan modern halefi için dokümantasyon
İlgili yazılar
Webpack'ten önce dosyaları Grunt ile birleştirir, jQuery spagettisiyle boğuşurduk. Frontend tooling'in manuel dosya yönetiminden build sistemlerine evrimi.
javascript · build-tools · technical-debt +2
esbuild, SWC ve Vite gibi native tool'ların webpack'in hız sorunlarını nasıl çözdüğü: build süreleri saniyelerden milisaniyelere böyle indi.
esbuild · build-tools · vite +4
CDK TypeScript Lambda için 9 bundler ve 3 cdk synth runner'ının ölçümlü karşılaştırması; her katman için varsayılan ve onu seçtiren kural.
aws-cdk · lambda · typescript +3
Nub ve Vite+, 2026'nın oxc tabanlı iki Rust araç zinciri; rakip gibi görünüp öyle değiller. Hangi ikilinin hangi repoda yeri olduğuna dair net bir kural.
javascript · typescript · vite +3
Bun ve Deno'yu AWS Lambda'da custom runtime ile çalıştırma: performans benchmark'ları, maliyet analizi ve production deployment pattern'leri.
lambda · javascript · serverless +2