HTML Imports (HTML İçe Aktarım) - Kısım 1
Neden Import?
Web’de farklı türdeki kaynak dosyalarını nasıl yüklediğinizi düşünün. JavaScript için <script src=""> tag’ini kullanıyoruz. CSS için ise <link rel="stylesheet" href=""> tag’ini kullanarak HTML sayfamıza kaynakları ekliyoruz. Bu örneklere resim, video ve ses dosyalarını da ekleyebiliriz. Peki makalemizde ne anlatmaya çalışıyoruz? Bu makalede kaynak dosyası olarak düşündüğümüz şey HTML ve biz bir HTML dosyasını başka bir HTML dosyasında çağırmayı öğreniyor olacağız. Peki daha önce bir HTML’i başka bir HTML dosyasında nasıl çağırıyorduk? Hemen bakalım:
- iframe : Şu an için gayet mantıklı bir çözüm gibi duruyor, fakat çok ağır. iframe’in içeriği sizin sayfanızdan tamamen farklı bir kaynağa bağlı ve sizin o sayfada bulunan HTML’e erişip şekillendirebilmeniz neredeyse imkansız.
- AJAX :
xhr.responseType="document"‘ı çok severiz, fakat bir HTML’i yükleyebilmek için JavaScript kullanmak mı? Kulağa pek hoş gelmiyor. - CrazyHacks™ : String’lere gömülü halde duran ya da comment’lerin içine gizlenmiş içerikler (örneğin
<script type="text/html">). Çok kötü bir seçim…
Buradaki ironiyi görebiliyor musunuz? İnternetin en temel kaynağı olan HTML’i import edebilmek için çok büyük ve gereksiz bir uğraş gerekiyor. Neyse ki Web Components imdadımıza burada yetişiyor.
Başlarken
Web Component’lerin bir parçası olan HTML Imports‘u, HTML’i başka bir HTML’in içine katmak için kullanabiliyoruz. Ayrıca HTML’i include ederken herhangi bir kısıtlamaya maruz kalmıyorsunuz. HTML’i eklediğimizde, .html uzantılı bir dosyanın içerebileceği CSS, JavaScript, resim gibi her şeyi de eklemiş oluyoruz. Başka bir deyişle HTML import, ilişkili HTML/JS/CSS dosyalarını eklemek için mükemmel bir araç.
Negatif Yönleri
O kadar övdük, şimdi de gelelim en büyük eksisine. Tarayıcı desteği. Maalesef şu anda sınırlı sayıda tarayıcı tarafından destekleniyor. Destekleyen tarayıcılar şu anda sadece Chrome ve Opera. Internet Explorer ve Safari gibi tarayıcılar destek vermiyor. Firefox’ta ise 32. sürümden itibaren about:config’den “dom.webcomponents.enabled” ayarı etkinleştirilerek destek açılabiliyor. Ayrıca 35. sürümden itibaren tam destek vermeye başlayacak. Daha fazla detay merak edenler Can I Use linkine bakabilirler.
Temelleri
Sayfaya HTML import etmek çok basit. <head> etiketinin içine <link rel="import"> olarak tanımlamamız yeterli:
<head>
<link rel="import" href="/dosya-yolu/dosya.html">
</head>Başka bir domainden dosya transferi yapmak için import edilecek yerin CORS (cross-origin resource sharing)-enabled olması gerekiyor.
<!-- Başka bir domainden alınan kaynakların CORS-enabled olması gerekli -->
<link rel="import" href="http://example.com/elements.html">Not:
Tarayıcının ağ yığını otomatik olarak aynı URL’den alınan istekleri teke indirir. Yani istek yapılan aynı URL’den sadece bir cevap alınır. Aynı konumdan kaç kere import edildiği önemli değil, sadece bir kere uygulanır.
Özellik Tespiti ve Destek
function supportsImports() {
return 'import' in document.createElement('link');
}
if (supportsImports()) {
// destekliyor!
} else {
// HTML dosyalarını yüklemek için diğer kütüphaneleri kullanmamız gerekiyor.
}Daha önce negatif yönlerden bahsederken belirttiğim gibi her tarayıcı tarafından desteklenmiyor. Chrome 31 ile daha yeni yeni bu özelliği görmeye başlamıştık. Chrome 36 ile de tam yerine oturdu denilebilir. Opera da 23. versiyon ile işler tıkırında gibi. Fakat diğer tarayıcılar için aynı şeyi söylemek zor. Bundan dolayı HTML Import yaygınlaşana kadar diğer tarayıcıları da desteklemesi açısından Polymer Project‘in HTML Import‘unu kullanmak en mantıklısı gibi duruyor. Başka bir yazımda Polymer Project’ten bahsedeceğim. Çok konu dışına çıkmamak için kısa kesip devam ediyoruz.
Kaynakları Gruplama
Import bize HTML/CSS/JS gibi kaynakları (hatta diğer HTML importları) tek bir import dosyasında gruplayabilmek için güzel bir olanak sunuyor. Bu noktada gerçekten etkili bir özellik. Bir tema, kütüphane ya da bir uygulama yazdığınızı düşünün. JS/CSS ve daha bir sürü import yapılması gerekiyor. Bunların hepsini tek bir dosyada depolayıp sonra da o dosyayı esas ekleyeceğiniz HTML dosyasına import edin. Ta-da! Tek bir HTML import ile bir sürü importu halletmiş olduk. Artık bunları başka bir dosyaya taşımamız gerektiğinde sadece bir tane import kopyalamamız yeterli olacaktır.
Gerçek hayattan bir örnek vermek gerekirse Bootstrap tam da bu örneğimize uyuyor. Bootstrap; CSS, JS ve font gibi bir sürü dosyadan oluşur, eklentileri için jQuery’ye ihtiyaç duyar ve birçok markup örneği sunar. Import Bootstrap gibi bir projede çok fazla esneklik sunabilir. İleride Bootstrap şu şekilde kullanılabilir bir hal alacaktır:
<head>
<link rel="import" href="bootstrap.html">
</head>Kullanıcı sadece bir HTML dosyası ekler. Onun için daha karışık bir kullanıma ihtiyaç yoktur. Bootstrap ile ilgili ihtiyacı olan her şey zaten o HTML dosyasının içindedir. bootstrap.html:
<link rel="stylesheet" href="bootstrap.css">
<link rel="stylesheet" href="fonts.css">
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="bootstrap-tooltip.js"></script>
<script src="bootstrap-dropdown.js"></script>
...
<!-- scaffolding markup -->
<template>
...
</template>Heyecan verici bir özellik. Şimdilik bu burada kalsın, biz devam edelim.
Yüklenme/Hata Olayları
<link> elementi import başarılı bir şekilde tamamlandıysa load olayını başlatır, eğer deneme başarısızsa (örneğin 404) error olayını başlatır. Tarayıcı importları <link> etiketini gördüğü an yüklemeye çalışır. İlerideki baş ağrılarının önüne geçmek için link elementine onload/onerror attribute’leri eklemeliyiz.
<script async>
function handleLoad(e) {
console.log('import yüklendi: ' + e.target.href);
}
function handleError(e) {
console.log('import yüklenirken hata: ' + e.target.href);
}
</script>
<link rel="import" href="file.html"
onload="handleLoad(event)" onerror="handleError(event)">İpucu:
Yukarıda görüldüğü üzere olay yakalayıcı (event handler) fonksiyonlarını importun üstüne yazdık. Tarayıcı import tag’ini gördüğü anda yüklemeye başlar. Eğer o anda script’imiz henüz okunmadıysa, tarayıcı konsolunda tanımsız fonksiyon hatası alırsınız ve fonksiyonlar işlenmez.
Aynı zamanda importu dinamik olarak oluşturabilirsiniz:
var link = document.createElement('link');
link.rel = 'import';
link.href = 'file.html';
link.onload = function(e) {...};
link.onerror = function(e) {...};
document.head.appendChild(link);İçeriği Kullanmak
Bir sayfayı include etmek onu doğrudan sayfada yazdırmak anlamına gelmiyor. “Parser, git benim için bu dokümanı getir ki ben istediğim zaman bu dokümanı kullanabileyim.” anlamına geliyor. İçeriği kullanabilmemiz için script yazmamız gerekli. Burada önemli nokta, importun sadece bir doküman olduğu. Artık bu gelen dokümanı standart DOM API’lerini kullanarak manipüle edebiliriz. Biz herhangi bir şey yapmazsak ekranda aldığımız veri gözükmeyecektir.
link.import
Import’un içeriğine erişebilmek için elementin .import property’sini kullanmamız gerekiyor.
var content = document.querySelector('link[rel="import"]').import;Aşağıdaki koşullardan birinin sağlanması durumunda link.import null değer döndürür:
- Tarayıcı HTML Import’u desteklemiyor ise.
<link>rel=“import” attribute’üne sahip değil ise.<link>DOM’a eklenmemiş ise.<link>DOM’dan silinmiş ise.- Kaynak dosyası CORS-enabled değil ise.
Tam Örnek
uyari.html dosyasının şunları içerdiğini varsayalım:
<div class="uyari">
<style scoped>
h3 {
color: red;
}
</style>
<h3>Uyarı!</h3>
<p>Bu sayfa yapım aşamasındadır!</p>
</div>
<div class="zaman-asimi">
<h3>Dikkat et!</h3>
<p>Bu içerik zaman aşımına uğramış olabilir!</p>
</div>Import eden sayfa, gelen HTML verisinin belirli bir bölümünü alabilir ve sayfaya kopyalayabilir:
<head>
<link rel="import" href="uyari.html">
</head>
<body>
...
<script>
var link = document.querySelector('link[rel="import"]');
var content = link.import;
// uyari.html'in içerisinden bir DOM elementi yakalıyoruz.
var el = content.querySelector('.uyari');
document.body.appendChild(el.cloneNode(true));
</script>
</body>Import edilen sayfa ile script
Importlar ana dokümanda değiller. Ana dokümanın uydusu gibi ona bağlılar. Fakat importlar yine de sanki ana dokümanımızdaymış gibi davranabilir. Bir import kendi dokümanındaki DOM’a erişebildiği gibi, onu import eden dokümanın DOM’una da erişebilir.
Örnek:
<link rel="stylesheet" href="http://www.example.com/styles.css">
<link rel="stylesheet" href="http://www.example.com/styles2.css">
<style>
/* Not: Importta bulunan <style> ana dokümandaki elementleri de etkiler. Bu nedenle ana dokümana da ayrı olarak eklenmesine gerek yoktur. */
#somecontainer {
color: blue;
}
</style>
...
<script>
// importDoc importun dokümanına işaret ediyor.
var importDoc = document.currentScript.ownerDocument;
// mainDoc importun yapıldığı ana dokümana işaret ediyor (bu sayfayı çağıran doküman).
var mainDoc = document;
// Bu importtaki ilk stil dosyasını alıyoruz ve
// onu import eden dokümana ekliyoruz (klonluyoruz).
var styles = importDoc.querySelector('link[rel="stylesheet"]');
mainDoc.head.appendChild(styles.cloneNode(true));
</script>Yukarıda küçük bir import dokümanı bulunuyor. Burada neler yaptığımızı tekrar anlatacak olursak; scriptin içinde import dokümanını (document.currentScript.ownerDocument) ve ana (import eden) dokümanı tanımlıyoruz. Ardından import dokümanındaki ilk stil dosyasını alıp bunu ana dokümanımıza ekliyoruz. Bana soracak olursanız oldukça harika.
Importta bulunan script hem doğrudan işlenebilir, hem de fonksiyon olarak tutulup ihtiyaç olduğunda ana dokümanda çağrılarak kullanılabilir.
Importtaki JavaScript kuralları:
- Importun içindeki script içeriğin bulunduğu pencerede işlenir. Yani window.document ana dokümana işaret eder. Bunun bize iki avantajı bulunuyor:
- Importta tanımlanan fonksiyonlar window’da (ana doküman) geçerli olur.
- Ana dokümanın içinde importun
<script>tag’lerini append etmenize gerek kalmaz. Importun içindeki script’ler zaten hemen işlenir.
- Importlar ana dokümanın parse edilmesini engellemez. Fakat içlerindeki script’ler sırayla işlenir. Bu da script sırasını koruyarak defer benzeri bir davranış elde ettiğiniz anlamına gelir.
Şimdilik bu kadar. Umarım faydalı bir yazı olmuştur. Yazımızın ikinci kısmında Web Component’lerinin iletimini ve performans faktörlerini göreceğiz ve son olarak unutmamamız gereken şeylere bakarak kısa bir tekrar yapacağız.