Erken Web Dönemi: Script'lerin Basit Olduğu Zamanlar

Webpack var olmadan önce, dosyaları Grunt ile birleştiriyorduk. React'tan önce, jQuery spagettisiyle boğuşuyorduk. Frontend tooling'in manuel dosya yönetiminden sofistike build sistemlerine nasıl evrildiği burada.

Şu sahneyi hayal edin: 2010 yılı, ve bir kurumsal website inşa ediyorsunuz. "Build process"iniz manuel olarak dosyaları bir js/ klasörüne kopyalamak, bunları bir shell script ile birleştirmek, ve script tag'lerinin doğru sırada olması için dua etmekten ibaret. Eğer fancysanız, belki bir Makefile'ınız vardı. Gerçekten fancysanız, production için JavaScript'inizi minify edebilen "Grunt" denen bu yeni şeyi keşfetmişsinizdir.

Bu dönemi yaşadım. Acıyı hatırlıyorum, o zamanlar devrimci hissettiren çözümleri ve imkansız görünen problemleri. Geriye bakınca, her limitasyonun bugünkü frontend ekosistemini şekillendiren inovasyona nasıl yol açtığı büyüleyici.

Pre-jQuery Karanlık Çağı (1995-2006)#

Modern tooling öncesi web development'ın bir resmini çizeyim. Website'ler inşa etmeye başladığımda, JavaScript ciddi uygulamalar için kullanacağınız bir dil değildi. Image rollover'lar ve form validation için kullanılırdı—eğer iddialıysanız.

Manuel Dosya Yönetimi Kabusları#

2000'lerin başında, tipik bir proje yapısı şöyleydi:

Text
website/
├── index.html
├── contact.html
├── js/
│   ├── utils.js
│   ├── validation.js
│   ├── slideshow.js
│   └── main.js
├── css/
│   ├── reset.css
│   ├── layout.css
│   └── styles.css
└── images/

Ve HTML'iniz şu canavarık gibiydi:

HTML
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/layout.css">
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <!-- content -->
    
    <script src="js/utils.js"></script>
    <script src="js/validation.js"></script>
    <script src="js/slideshow.js"></script>
    <script src="js/main.js"></script>
</body>
</html>

Problemler anında ve acı vericiydi:

  1. Sıra bağımlılığı cehennemi: main.js'i utils.js'den önce taşı ve her şey bozulur
  2. Global namespace kirliliği: Her değişken global scope'ta yaşardı
  3. Dependency management yok: Hangi script'in hangi script'e ihtiyacı olduğunu manuel takip etmek zorundaydınız
  4. Performance: JavaScript dosyaları için 15 ayrı HTTP request normalti
  5. Cache busting: Dosya yollarına manuel olarak ?v=1.2.3 eklemek
  6. Development vs production: Farklı environment'lar için farklı HTML dosyaları

Bir kez, slideshow'un production'da neden bozulduğunu debug etmek için bütün bir gün harcadım, sadece production server'ın case-sensitive olduğunu ve bir script tag'de SlideShow.js yerine slideshow.js yazması gerektiğini keşfetmek için. Bunlar zamanımızı tüketen problemlerdi.

Browser Uyumluluğu: Internet Explorer Yılları#

Cross-browser uyumluluğu sadece "güzel olur" değildi—her teknik kararı şekillendiren birincil kısıttı. Internet Explorer 6'nın %60 market share'i vardı ve web standartlarının kendi yorumu vardı.

Günlük yazdığımız kod türü:

JavaScript
function addEvent(element, event, handler) {
    if (element.addEventListener) {
        element.addEventListener(event, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent('on' + event, handler);
    } else {
        element['on' + event] = handler;
    }
}

function getXMLHttpRequest() {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        try {
            return new ActiveXObject('Msxml2.XMLHTTP');
        } catch (e) {
            return new ActiveXObject('Microsoft.XMLHTTP');
        }
    }
    return null;
}

Her basit operasyon browser detection ve fallback'ler gerektiriyordu. Feature'lar inşa etmekten çok compatibility layer'ları yazmaya zaman harcıyorduk.

jQuery Devrimi (2006-2012)#

jQuery 2006'da geldiğinde, büyü gibi hissettirdi. John Resig browser uyumluluğu problemini "daha az yaz, daha fazla yap" diyen zarif bir API ile çözmüştü. Ama daha da önemlisi, jQuery daha sonra modern tooling'de temel olacak konseptleri tanıttı.

Abstraction'ın Gücü#

JavaScript
// jQuery öncesi
function fadeOut(element) {
    var opacity = 1;
    var timer = setInterval(function() {
        if (opacity <= 0.1) {
            clearInterval(timer);
            element.style.display = 'none';
        }
        element.style.opacity = opacity;
        element.style.filter = 'alpha(opacity=' + opacity * 100 + ")";
        opacity -= opacity * 0.1;
    }, 50);
}

// jQuery ile
$('#myElement').fadeOut();

Bu sadece syntactic sugar değildi—felsefi bir değişimdi. jQuery abstraction layer'larının gücü feda etmeden karmaşıklığı gizleyebileceğini kanıtladı. Bu konsept daha sonra her frontend framework'ü etkileyecekti.

jQuery Plugin'leri: İlk Package Ecosystem#

jQuery plugin'leri web'in ilk gerçek package ecosystem'iydi. Datepicker mi lazım? $('#myInput').datepicker(). Carousel mi istiyorsun? $('.carousel').slick().

Ama tooling perspektifinden işin ilginç kısmı buradaydı: jQuery plugin'lerini yönetmek vanilla JavaScript ile sahip olduğumuz aynı problemleri daha büyük ölçekte ortaya çıkardı.

2010'da tipik bir jQuery projesi şöyleydi:

HTML
<script src="js/jquery-1.4.2.min.js"></script>
<script src="js/jquery.ui.core.js"></script>
<script src="js/jquery.ui.datepicker.js"></script>
<script src="js/jquery.slick.min.js"></script>
<script src="js/jquery.validation.min.js"></script>
<script src="js/jquery.fancy-input.js"></script>
<script src="js/app.js"></script>

Problemler Başarıyla Birlikte Büyür#

jQuery projeleri büyüdükçe, saf JavaScript developer'larının karşılaşmadığı yeni problemler ortaya çıktı:

Plugin Çakışmaları: İki plugin de $.fn.slider'ı modify ediyordu ve hangisinin kazandığını debug etmek kabustu.

Version Cehennemi: jQuery UI 1.8, jQuery 1.4 ile çalışıyordu ama 1.5 ile değil. jQuery'yi upgrade etmek potansiyel olarak her plugin'i bozabilirdi.

Performance Sorunları: 15 jQuery plugin'i yüklemek, her plugin'in fonksiyonalitesinin sadece %10'unu kullanıyor olabileceğiniz halde 300KB JavaScript indirmek demekti.

Module System Yok: Her şey hala globaldi. $.myPlugin, $.myOtherPlugin ile çakışıyordu ve büyük uygulamalarda scope sorunlarını debug etmek vahşetti.

2011'de üzerinde çalıştığım bir production uygulamasından kod parçası:

JavaScript
$(document).ready(function() {
    // 12 farklı plugin'i initialize et
    $('.datepicker').datepicker();
    $('.slider').slider();
    $('.tooltip').tooltip();
    $('.validate').validate();
    $('.tabs').tabs();
    $('.accordion').accordion();
    $('.modal').modal();
    $('.carousel').carousel();
    $('.autocomplete').autocomplete();
    $('.sortable').sortable();
    $('.draggable').draggable();
    $('.charts').charts();
    
    // Sonra 500 satır custom JavaScript
    // her yerde global state'i modify ediyor
});

Takımlar büyüdükçe bunu yönetmek imkansız hale geldi. Güvenli refactor yapamıyordunuz çünkü herhangi bir değişiklik başka bir developer'ın deine global state'e bağımlı kodunu bozabilirdi.

"Build Tool"ların İlk Denemeleri#

2009-2010'da, akıllı developer'lar pattern'leri fark etmeye ve çözümler inşa etmeye başladılar. Bunlar bugün bildiğimiz sofistike build tool'lar değildi, ama manuel dosya yönetiminin sürdürülebilir olmadığının ilk fark edilişiydi.

Shell Script'ler ve Makefile'lar#

İlk "build tool"lar tam anlamıyla shell script'lerdi:

Bash
#!/bin/bash
# build.sh

echo "Building application..."

# CSS dosyalarını birleştir
cat css/reset.css css/layout.css css/styles.css > dist/app.css

# JS dosyalarını birleştir
cat js/utils.js js/validation.js js/main.js > dist/app.js

# Minify et (YUI Compressor için Java kuruluysa)
java -jar yuicompressor-2.4.7.jar dist/app.css -o dist/app.min.css
java -jar yuicompressor-2.4.7.jar dist/app.js -o dist/app.min.js

echo "Build complete!"

Sofistike takımlar Makefile kullanırdı:

makefile
CSS_FILES = css/reset.css css/layout.css css/styles.css
JS_FILES = js/utils.js js/validation.js js/main.js

dist/app.css: $(CSS_FILES)
	cat $(CSS_FILES) > dist/app.css

dist/app.min.css: dist/app.css
	java -jar yuicompressor-2.4.7.jar dist/app.css -o dist/app.min.css

dist/app.js: $(JS_FILES)
	cat $(JS_FILES) > dist/app.js

dist/app.min.js: dist/app.js
	java -jar yuicompressor-2.4.7.jar dist/app.js -o dist/app.min.js

clean:
	rm -rf dist/*

build: dist/app.min.css dist/app.min.js

Çözemediğimiz Problemler#

Bu erken build denemeleri temel concatenation ve minification problemlerini çözdü, ama daha derin sorunları ortaya çıkardı:

Dependency Resolution: Hala dosyaların sırasını manuel yönetiyorduk. main.js, utils.js'ten bir fonksiyona bağımlıysa, utils.js'i önce listelemeyi hatırlamak zorundaydık.

Incremental Build'ler: Her değişiklik her şeyi yeniden build etmek demekti. utils.js'te tek karakter değişikliği bütün JavaScript bundle'ını yeniden build'lemeyi tetikliyordu.

Asset Management: Resimler, fontlar ve diğer asset'ler hala elle yönetiliyordu. Cache busting manuel olarak dosya isimlerini güncellemeyi gerektiriyordu.

Development Workflow: Build adımı o kadar yavaştı ki çoğu developer development sırasında atlıyordu, bu da ayrı dosyalarla çalışırken işe yarayıp concatenate edilince bozulan klassik "benim makinemde çalışıyor" problemlerine yol açıyordu.

Bower Devrimi: Package Management Geldi#

2012'de Twitter, Bower'ı release etti ve gelecek gibi hissettirdi. Sonunda frontend bağımlılıkları için gerçek bir package manager'ımız vardı:

Bash
bower install jquery
bower install jquery-ui
bower install bootstrap

ZIP dosyaları indirip manuel olarak projenize kopyalamak yerine, Bower bağımlılıkları otomatik halledecekti. Projeniz bir bower.json dosyası alıyordu:

JSON
{
  "name": "my-awesome-app",
  "dependencies": {
    "jquery": "~1.8.0",
    "jquery-ui": "~1.9.0",
    "bootstrap": "~2.3.0"
  }
}

Vaat ve Problemler#

Bower indirme ve versiyon yönetimi problemini çözdü, ama yenilerini yarattı:

Flat Dependency Tree: Bower her şeyi bower_components/ içine nesting olmadan koyuyordu. İki package farklı jQuery versiyonlarına bağımlıysa, Bower size seçim yaptırıyordu—ve genelde bir şeyleri bozuyordu.

Build Integration Yok: Bower dosyaları indiriyordu, ama hala bunları HTML'inize veya build script'lerinize manuel eklemeniz gerekiyordu.

Version Çakışmaları: Flat dependency tree, dependency çakışmalarının developer'a itilmesi demekti. "Package A'nın jQuery 1.8'e ihtiyacı var, Package B'nin jQuery 1.9'a, sen hallet."

2012'de tipik bir Bower projesi şöyleydi:

HTML
<!-- Development -->
<script src="bower_components/jquery/jquery.js"></script>
<script src="bower_components/underscore/underscore.js"></script>
<script src="bower_components/backbone/backbone.js"></script>
<script src="bower_components/bootstrap/js/bootstrap.js"></script>
<script src="js/models/user.js"></script>
<script src="js/views/userView.js"></script>
<script src="js/app.js"></script>

Production için concatenate ve minify etmek için hala build process'e ihtiyacınız oluyordu ve hala script sırasını manuel yönetmeniz gerekiyordu.

Geriye Bakış: Modern Tooling'i Şekillendiren Dersler#

Bu dönemi yaşamak, endüstriye modern tooling tasarımını doğrudan etkileyen değerli dersler öğretti:

Manuel Processs'ler Scale Etmiyor#

Manuel dosya yönetimi gerektiren her çözüm, projeler büyüdükçe sonunda çöküyordu. Bu, modern build tool'ların automation-first yaklaşımına yol açtı.

Sıra Bağımlılıkları Şeytani#

Script'lerin load sırasını manuel yönetmek zorunda olmak sürekli bug kaynağıydı. Bu kavrayış, bağımlılıkları explicit yapan module sistemlerine (CommonJS, AMD, ES modules) yol açtı.

Flat Dependency Tree'ler Çakışma Yaratır#

Bower'ın flat dependency yaklaşımı çözdüğünden fazla problem yarattı. Bu deneyim npm'in nested dependency tree tasarımını ve pnpm'in sofistike resolution algoritmasını bilgilendirdi.

Developer Experience Önemli#

Development ve production environment'ları arasındaki fark sürekli sürtünme yaratıyordu. Modern tool'lar hot reloading ve instant feedback loop'lar aracılığıyla dev/prod parity'yi prioritize ediyor.

Lock-in Olmayan Abstraction#

jQuery'nin başarısı, altta yatan DOM'a doğrudan erişime izin verirken karmaşıklığı gizlemesinden geliyordu. Modern framework'ler bu pattern'i takip ediyor—escape hatch'leri olan güçlü abstraction'lar.

Devrim İçin Sahne Hazır#

2012'ye kadar, frontend tooling'in çözmesi gereken çekirdek problemlerin çoğunu belirlemiştik:

  • Dependency management: Manuel script sıralaması sürdürülemezdi
  • Asset optimization: Concatenation ve minification açıkça gerekliydi
  • Development workflow: Development ve production arasındaki fark çok genişti
  • Browser compatibility: Abstraction layer'ları esastı
  • Code organization: Global scope pollution sona ermek zorundaydı

Ayrıca geleceği işaret eden erken çözümlerle deneyim yapmıştık:

  • Shell script'ler ve Makefile'larla build automation
  • Bower ile package management
  • jQuery ile abstraction layer'ları
  • Modülerliğin gücünü gösteren plugin ecosystem'ları

Bir sonraki devrim için sahne hazırdı: uygun task runner'lar, module bundler'lar ve modern JavaScript framework'lerinin doğuşu. Ama bu, bu serinin bir sonraki bölümünün hikayesi.

2012'de bilmediğimiz şey, bu problemlerin çözümlerinin frontend development hakkında düşünme şeklimizi temelden değiştireceğiydi. Sonraki birkaç yılda ortaya çıkan tool'lar sahip olduklarımızın sadece daha iyi versiyonları değildi—endüstriyi yeniden şekillendireceği tamamen yeni yaklaşımlardı.

Bir sonraki bölümde, build automation problemini çözmek için Grunt ve Gulp'un nasıl ortaya çıktığını, RequireJS ve Browserify'ın uygun module sistemlerini nasıl tanıttığını ve Webpack'in bundle'ı uygulama yaparak her şeyi nasıl değiştirdiğini keşfedeceğiz.

Frontend Tooling'in Evrimi: Senior Mühendis Perspektifi

jQuery dosya birleştirmesinden Rust-powered bundler'lara - frontend tooling'in gerçek production problemlerini nasıl çözmek için evrildiğinin anlatılmamış hikayesi, savaş hikayeleri ve pratik deneyimlerle.

İlerleme1/4 yazı tamamlandı
Loading...

Yorumlar (0)

Sohbete katıl

Düşüncelerini paylaşmak ve toplulukla etkileşim kurmak için giriş yap

Henüz yorum yok

Bu yazı hakkında ilk düşüncelerini paylaşan sen ol!

Related Posts