Turbo nedir? Yenir mi?

Benim yazılıma ilk başladığım günden beri sürdürdüğüm tuhaf bir alışkanlık vardır ki bu da not tutarak çalışmaktır. Önce elime kağıt kalem alırım, okuduklarımdan ufak notlar alırım ve neticesinde teoriyi kaptığımı düşününce kollarımı sıvar işim içine girerim. :slight_smile: Bu yazı da aldığım notların toplamından oluşuyor. Yazıyı daha önce Gitbook gibi bir yerde yayınlamayı düşündüm, ancak hem erişime olan kolaylığı hem de bu sitenin aylardır böyle çiğ bir şekilde durmasının içimi acıtması sebebiyle bu sitede yayınlamaya karar verdim.

Turbo nedir?

Günümüzde frontend çatıları çok gelişti ve gayet sağlam bir yere vardı. React, Vue ve benim kişisel olarak ilgilenmiş olduğum Svelte şahane frameworkler doğrusu. Pek çok durum için güzel çözümleri ve React Native gibi çeşitli platformlar için güzel çözümleri var. Ancak bu frameworkler öyle kendi başına öyle büyük ki Backend’den rol çalıyorlar. Mesela canımız ciğerimiz Rails, bu frameworklerle çalışırken json al - json verden öteye geçmeyen gerzek bir şeye dönüşüyor. Birbiri ile alakası olmayan iki farklı sunucu birbiriyle anlaştırmaya çalıştığınızı hissediyorsunuz.

JSON’un ne olduğunu bilmeyen dostlar için: Sunucudan dönen mesajların tipi JSON’dur. Rails normalde HTML döner, ancak React/Vue/Svelte gibi frameworklerle çalışırken onay veya hata mesajı içeren mesajlar döner.

Aslında sorun şurada, bu frameworkler web sayfasını tamamen JavaScript üzerinde tutmak için tasarlandı ve sunucudan cevap almak/tarayıcıya html yollamak prensibi ile çalışıyor. Bu sefer şöyle bir şey beliriyor kafamda. Aslında Rails gibi devasa ve kafa karıştırıcı bir backend yerine Sinatra/Flask/Express.js gibi daha ufak, daha “işlevsiz” yapılarla da çalışabiliriz. Böylece pekâlâ Rails’in ne döneceğini, ne yapacağını, nerede html nerede json döneceğini uzun düşünmek yerine her şeyi doğrudan json dönebiliriz, üstelik hızlılar da. Ama doğrusu Rails’in getirdiği pek çok pratikliği terk etmenin karşılığı uzun geliştirme süreçleri oluyor.

Şimdi Turbo dediğimiz şey ise bizim karşımıza şöyle bir şeyle çıkıyor; Aslında derdimiz havalı frontend zamazingoları yapmak değil mi? Yani aslında ihtiyaçlarımız öyle az ki, bu ihtiyaçlar için mesela React ve Redux aslında çok aşırı kaçıyor. Turbo ise, bu şaşalı frontend frameworklerine karşı şöyle bir çözüm sunuyor: Sıkça arzu edilen frontend araçlarına HTML etiketleri ile sunalım. Geri kalanını da sade bir framework olan Stimulus’la halledelim. Böylece:

  1. Bu şaşalı frameworklere gerek kalmaz, Rails ön planda olur.
  2. JSON’un mantığını hem backende hem de frontende anlatmaya çalışmak yerine tek bir yere anlatırız. (Diğer bir dille: Süreden kazanırız.)
  3. Daha az JS ile yazarız ve daha çok Ruby, pardon, en çok sevdiğimiz dille çalışmış oluruz.

Yenir mi?

Yenmez. Yiyecek bir şeyler ararsanız ona da çözümümüz var: Fellah

Bu Turbo neyden oluşuyor?

Aslında Turbo çok ufak bir yapı, sadece üç araca sahip ancak bu üç araç olabildiğince Frontend’e iyi bir yaklaşım getiriyor.

  • Turbo Drive: Sayfalar arasında kesintisiz gezinti sağlar. Bunu şöyle anlatabilirim. Google’ı açın ve bir şeyler yazın. Sayfa tamamen yenilenmeksizin içeriği değişir ve aramanız tarayıcı geçmişine kaydedilir. Ama Google’dan başka bir sayfaya geçince tarayıcının içeriği boşalır ve yeni sayfayı bekler. Google sayfaları arasında gezinmeyi hızlandırmak için bir “kesintisizlik” vardır. Turbo Drive ise, bu kesintisiz gezinmeyi sağlar.

  • Turbo Frames: Aslında bu Frames denen nanenin iki özelliği var. Birincisi, sayfaları eğer turbo frames ile gruplandırırsanız aslında hepsini “lazy loading” denen bir mekanizmaya bağlamış oluyoruz. Bu lazy loading, Türkçesi ile “tembel yükleme”, sayfanın bileşenlerinin göründüğü anda yüklenmesini sağlar ki hem koca bir sayfayı bir anda tarayıcıya okutmamış oluruz hem de sunucuyu gerektiğinde meşgul ederiz. İkincisi başka bir adresteki html dosyasını kendi içinde görüntülenebiliyor. Zaten “Frames” ismi eskiden kullanılan “iframe” etiketine gönderme.

  • Turbo Streams: Bu kısım Turbo’nun en civcivli kısmı. Ana işlevi sayfayı güncel tutmak ve sunucu ile aradaki bağlantıyı düzenlemek. Sayfanın içerisinde “template” etiketleri içerisinde görünmez bir veri tutulur ve bu görünmez veri vakti zamanı geldiğinde sunucudan gelen cevaplara göre bir hedefe yönlendirilir. Zaten JSON’u aradan çıkaran şey de bu Stream kardeş. Sunucudan JSON alıp JavaScript’e “Bak bakayım ne demiş?” diye sordurmak yerine direkt sunucudan cevabı alıp bir HTML bloğunu işleme sokmuş oluyoruz.

Bir de bu üç parçanın dışında bir parça daha var: Turbo Native. Turbo Native ile iOS ve Android uygulamasına çevirebilirsiniz uygulamalarınızı. Ancak doğrusu Turbo Native’i Turbo’nun esas parçalarından birisi olarak değil, eklentisi olarak gördüğüm için bu yazıda ele almayacağım. Çünkü maksadım Turbo’nun ne olduğunu ele almak.

Şimdi yavaş yavaş bu üstte bahsettiğim araçları daha detaylıca ele alalım.

Daha önce Turbodrives olarak nam salmış olan, 7 sayfanın fatihi: Turbo Drive

  1. Linkleri takip eder
  2. Form kayıtlarını takip eder
  3. Tamamen yenilemeye gerek bırakmadan sayfayı günceller

Sayfadan sayfaya geçişleri sanki bir DOM eventiymişçesine sağlar. (DOM: HTML etiketlerinin tarayıcıda işlendiği alan.) Gidilecek sayfayı geçmişe kaydeder, yeni bir ağ isteği yaratır, belleğe işler ve bunları yaparken de sayfanın kontrolünü terk etmez.

Bir sayfayı ziyaret etmenin iki yolu vardır.

  1. Uygulama içi Ziyaretler - Application visit
    “Advance” (İlerlemek) ve “replace” olarak ikiye ayrılır. Advance, varsayılan olarak gidilen yeni bağlantıyı tarayıcı geçmişine kaydeder. Replace ise sadece sayfayı günceller, yeni bir bağlantıya ulaşmış gibi görünmez. Uygulama içi ziyaretler Turbo.visit(hedef) komutu ile veyahut Turbo drive bağlantısı ile çalışır. Şu şekilde bir replace bağlantısı tanımlayabiliriz:
<a href="/fellahkoftetarifi" data-turbo-action="replace">Dünyanın en iyi yiyeceği</a>

veya JavaScript ile:

Turbo.visit("/fellah-kofte-ve-illuminati-gercekleri", { action: "replace" })

Replace yerine Advance de yazabilirsiniz, ancak zaten varsayılan bağlantı şekli Advance olduğu için pek de gereği yok sanki. (Emin değilim, bana da sormayın.)

  1. Restorasyon Ziyaretleri - Restoration Visit
    Bunlar uygulama içinden değil dışından olan ziyaretlerdir. Aslında şöyle. Adamın birisi tarayıcıda ileri - geri tuşları kesince basıyor. Uygulama içi ziyaretleri kullanırsak uygulama saçma sapan bir yere doğru yol alır. Bunun yerine Turbo, bunları bir restorasyon ziyareti olarak ele alır. Siz de mutlu olursunuz, ne yaptığını bilmeyen son kullanıcı denen canavar da, Turbo Drive da.

Ziyaret başlamadan önceki süreçleri JavaScript ile yönetmek mümkündür. Bunun için şu aşağıdaki DOM eventleriyle yüz göz olmanız gerekmektedir:

  1. turbo:before-start
  2. turbo:before-render
  3. turbo:before-fetch-request

Hadi biraz daha çılgınca şeyler yapalım. Turbo Drive sadece sunucudan gelen mesajları temsil eden GET metotları yollamaz. Aynı şekilde sunucuya bazı mesajlar yollayabilir. Mesela bir bağlantının gözünün yaşına bakmadan DELETE mi yollamak istiyorsunuz?

<a href="/beni-yak-kendini-yak" data-turbo-method="delete">Durup dururken bir şeyleri sil</a>

Yine de, bazı erişilebilirlik durumları için bu tarz şeyler için formlar yollamanızı tavsiye ediyorlar.

Peki sayfalar yüklenirken bir ilerleme çubuğu gösterebilir miyiz? Elbette. Sadece CSS ile “.turbo-progress-bar” sınıfını değiştirin.

// Şeytani bir gri bar için:
.turbo-progress-bar {
  height: 666px;
  background-color: #666666;
}
// Gizlemek için:
.turbo-progress-bar {
  visibility: hidden;
}

Pekâlâ… Turbo Drive ile ilgili anlatacaklarım, ziyadesiyle kendimce önemli gördüklerim bu kadar. Bunları şöyle özetleyebilirim:

  • Sayfaları tamamen kapanmadan yükler.
  • Delete gibi istekler yollanabilir.
  • Yüklemeden önce ek işlemler yapar.

Şimdi ise web yazılımcılığının unutulmuş mirasına gelelim.

"iframes"in oğlu, HTML’nin ustası: Turbo Frames

Bu sanırım Turbo’nun hem en kolay anlaşılan kısmı hem de en güçlü silahı. Kullanması çok basit, gerçekten. Bütün olay şu:

  <turbo-frame id="tekTekYuklenirseSorunOlmayacakAncakHepBeraberYuklenmemesiGereken">
    <h1>Dünyanın büyük resmi</h1>
    <img src="hiçbir_yere_sığmayan_obez_bir_kedinin_70MBlık_resmi.jpg" alt="Tatlı bir kedi"> 
  </turbo-frame>

Üstte görmüş olduğunuz kullanımın amacı “lazy load” mekanizmasını devreye sokmaktır. Yani siz bu resmi görene kadar gördüğünüz turbo-frame etiketinin içeriği yüklenmez. Bu mantığı mesela Instragram görmüşsünüzdür. Dipsiz kuyu, kaydır kaydır bitmiyor. Tabii ki “lazy load” mekanizması dipsiz kuyular yaratmak için kullanılabilir ancak buradaki amaç her veriyi gerektiğince yüklemek. Mesela adam girdiğiniz sayfadan istediğini aldı çıktı, durup dururken 70mblık resmi yükletmenin bir anlamı yok gördüğünüz gibi.

Ancak turbo-frame etiketinin aslında bir amacı daha var ki, o da başka bir adresteki HTML dosyasını içeri aktarmaktır. Mesela şunu dikkatlice inceleyin:

<turbo-frame id="tepsi" src="/hayko_cepkin_yoksa_aslında_suleyman_demirel_mi.html">
     Az sonra sizi içeri alacağım, lütfen bekleyin.
</turbo-frame>

Src ile gösterilen adresteki HTML sayfası içeri aktarılacaktır. Yalnız dikkat etmelisiniz ki, dışa aktarılan HTML sayfası içe aktaran DOM yapısının bir parçası olacaktır. Eski iframes sisteminde böyle bir şey yoktu, sayfa içinde sayfa gibi tuhaf bir şey ortaya çıkıyordu. Bu sayede tek bir CSS dosyası tarafından biçimlendirilebilir, tek bir JavaScript dosyası ile yönetilebilirler.

Ek olarak başka bir HTML dosyasını içeri aktaran turbo-frame etiketleri “lazy-load” olarak yüklenmez.

Özetleyelim:

  1. Turbo Frames, sayfanın tembelce yüklenmesi gereken parçalarını içine alan bir kaptır.
  2. Turbo Frames, başka HTML sayfalarını içinde barındırabilir.

Ölüyü Dirilten Turbo Stream

Tamam, kabul etmeliyim ki Turbo Stream benim de anlamakta en zorlandığı kısımlardan birisi. Bu yüzden size aktarırken hata yapabilirim, zira elimde notlarımı aldığım deftere baktığımda defter sayfasının karalanmamış bir kısmı yok. (Zaten el yazım fellah köftesi biçimsizliğinde, onun da etkisi olabilir.)

Turbo Stream, kaba hesap sunucu ile tarayıcı arasındaki iletişimi sağlayan önemli bir unsur. Sunucu Turbo Stream ile bilgilendirilebilir, tarayıcı da sunucudan gelen veriye göre sayfayı güncelleyebilir. HTML üzerinde şöyle görünür:

# Action çeşitli parametreler alabilir.
# Target ise hedef HTML/DOM öğesinin ID'sidir. 
<turbo-stream action="append" target="minnoş_kedi_resimleri">
  # Template etiketleri arasındakiler sayfada görüntülenmez.
  # Template etiketi action'a göre işlenir.
  # Burada, target ile gösterilen hedefin sonuna eklenecektir.
  <template>
    <div id="kediş_1">
      Bu kısım, target ile gösterilen id'ye eklenecektir.
    </div>
  </template>
</turbo-stream>

Sunucudan ise Turbo Stream kendisine has bir “Response”/“Cevap” etiketiyle beraber kullanılır. Bu da Rails üzerinde üç aşağı beş yukarı buna benzer:

def create
    @kedi = Kedi.new(pisi_pisi_params)

    respond_to do |format|
      if @kedi.save
        format.html { redirect_to @player, notice: "Miyav Başarılı" }
        format.turbo_stream
      else
        format.html { render :new, status: :unprocessable_entity }
      end
    end
 end

Turbo Stream bu örnekte bir hedefe öğe eklemek için kullanılmış olsa da, “action” isimli etiketinde şunları da barındırır:

  • prepend
    Template içindeki öğe hedefin (target ile gösterilen id) başına eklenir
  • replace
    Template içindeki öğe hedefin içeriği ile yer değiştirir.
  • update
    replace ile hemen hemen aynı işi gördüğünü düşündüm, ama ben de anlamadım doğrusunu isterseniz.
  • remove
    Hedefi siler. Yalnız, template ve içeriği görmezden gelinir. Boş bırakılması makbuldür.
  • before
    Hedeften öncesine kendisini ekler.
  • after
    Hedeften sonrasına kendisini ekler.

Dilenirse “target” çoklu hedeflere yönlendirilebilir. Sadece target yerine targets yazmanız ve nokta ile başlayan CSS class’ının (sınıfının) adını yazmalısınız. Örneğin:
targets=".liste"

Yazı burada sona eriyor. Eğer yazıda bir eksiklik, ya da fazlalık, görürseniz eklemeler yapmaktan ve hataları düzeltmekten çekinmeyin. Neticede tek oturuşta bir ön hazırlık olmaksızın yazılmış bir yazı bu, muhakkak içeriğinde hatalar olacaktır - yaklaşık 6 a4 sayfası ve 1.605 kelime tutuyor. :slight_smile:

Güzel özet olmuş. Eline sağlık :clap:

3 Likes

Eline sağlık.
Nerede fellah köftesi yemeyi önerirsin? :slight_smile:

1 Like

Galata Kulesi’nin orada “Turbocu DHH Usta” var. Denemediysen kesin bir şans ver.

1 Like

Ben hep evde yedim, ama duyduğuma göre Adana’da çok iyi yapıyorlarmış. Artık Rubydir Turbodur anlatırsınız dükkan sahibine. :smiley:

Fellah görünce, güzel bir yer önerisi gelir diye umutlanmıstım. :’)

1 Like

Keşke bilsem :’) Yolunuz Galata’ya düşerse bir su turbocuyu arayın derim.