Kişisel web tasarım ve kodlama blogu. Web tasarımı ve kodlama araçları ile ilgili bilgiler ve yardımcı dökümanlar.

Kod yazmak sanattır...

gokhankr.com

Blogger tarafından desteklenmektedir.

Vuex Store - Mutations'da Sabitler ve Senkronize


Mutasyonlar İçin Sabitleri Kullanmak

Çeşitli Flux uygulamalarında mutasyon türleri için sabitlerin kullanılması yaygın olarak görülen bir durumdur. Bu, kodun linter gibi araçlardan yararlanmasını sağlar ve tüm sabitleri tek bir dosyaya koymak, beraber çalıştığınız geliştiricilerin tüm uygulamada hangi mutasyonların mümkün olduğunu bir bakışta görmelerini sağlar:


// mutasyon-listesi.js
export const MUTASYONLAR = 'MUTASYONLAR'


// store.js
import Vuex from 'vuex'
import { BIR_MUTASYON } from './mutasyon-listesi'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // Sabit'i "ES2015 Computed Property Name" özelliği ile
    // bir fonksiyon adı olarak kullanabilirsiniz
    [BIR_MUTASYON] (state) {
      // bir mutasyon gerçekleştir
    }
  }
})

Sabitlerin kullanılıp kullanılmaması büyük ölçüde bir tercihtir ve birçok geliştiricinin olduğu büyük projelerde yardımcı olabilir, ancak beğenmezseniz tamamen isteğe bağlıdır.

Mutasyonlar Senkron Olarak Çalışmalıdır

Hatırlanması gereken önemli bir kural, mutasyonların eşzamanlı olması gerektiğidir. Neden mi ? Aşağıdaki örneği düşünün:


mutations: {
  birMutasyon (state) {
    api.callAsyncMethod(() => {
      state.miktar++
    })
  }
}

Şimdi uygulamada hata ayıkladığımızı ve devtool üzerinden Vue'nun Mutations loglarına baktığımızı düşünün. Kaydedilen her mutasyon için, devtool, "önce" ve "sonra" olarak durumları anlık görüntü biçiminde yakalama ihtiyacı duyacak. Bu yüzden, yukarıdaki örnekte olduğu gibi mutasyonun içindeki eşzamansız bir geri çağırma fonksiyonu bunu imkansız kılar. Mutasyon işlendiğinde callback o anda anlık olarak çağrılmayacağı için devtool'un callback'in ne zaman çağrılacağını bilmesinin bir yolu yoktur. Dolayısıyla callback ile gerçekleştirilen herhangi bir mutasyon işlemi takip edilemez!

Mutasyonlar ile ilgili anlatım bilgileri bu kadardı. Bundan sonraki süreçte Actions'lara değineceğiz. Teşekkürler.

Bootstrap - 12 yerine 24'lü Izgara Yapısı


Son yaptığım projemi Figma'da tasarımladıktan sonra HTML üzerine dökerken çok enteresan bir durumla karşılaştım. Yatay eksende 3 bölüme ayırdığım bir Section içerisinde sol ve sağ bloklar içerisinde tasarımlamış olduğum kartlarım ile orta bölüme de dikey olarak attığım ufak bir çizgi Bootstrap'ın grid yapısına uymadı. 

İçeriği orantılı bir şekilde ortalamam için sağa ve sola .col-5, .col-5 i ve orta bölüme de kalan .col-2 yi vermem gerekiyordu. Yani örnekteki gibi:

 

Tahmin edebileceğiniz üzere bir tane çizgi için orta bölüm aşırı geniş durdu ve tasarımın görünümünde biçimsizliğe neden oldu:

Dolayısıyla CSS üzerinden bir çözüm arayışına giriştim.

Çözümüm

Çok ta uğraştırıcı bir çözümü yoktu tabi. Sağ ve sol karta width:108%; verdim ve sağ tarafa da margin-left:-8%; verip mobilde de bunu sıfırlayınca sütunlar üzerinde herhangi bir değişiklik yapmadan meseleyi çözmüş oldum. Ancak tasarım düzeninde biraz oynama yapmak durumunda kaldım.

Sonuç

Peki bu ızgara sisteminin hep klasik web sayfaları ortaya koymak olduğunu gören bir tek ben miyim ? Hayır. Bu sistemin tasarımı sabit bir ızgara sistemine bağımlı kıldığını söyleyen çok insan var. Ancak nasılsa bu durum halen Bootstrap 5 üzerinde de devam etmekte. Aslında benim rahatsız olduğum tek mesele bu da değil. Bootstrap Container boyutu genişliği de var. Nedendir bilmem ama bir ekran neden 1140px içerisinde sabitlenmek zorunda ? 

Farklı düşünenler var mıdır bilemem ama, Bootstrap Container içerisine bulunan bir web sitesini en az 22" bir LCD üzerine çektiğim zaman kısa tabiriyle cücük gibi duruyor. En azından son zamanların Flex Layout düzeni ile kodlanan Bulma CSS bu konuda biraz daha elini genişletmiş ve Container boyutunu 1152px'e çekmiş. Deneme yaptığımda tabiki de Bootstrap'a göre daha ferah bir görünüm sağlıyor. 12px ne kadar etkili olabilir düşüncesinde olabilirsiniz ama evet gerçekten görünüme çok etki ediyor kesinlikle deneyin. Ayrıca 1488px ve üzeri için de 1344px lik bir Container genişliği belirlemiş.

Bulma İçin: https://bulma.io/

Yazımın sonuna geldiğimde ızgara konusuda artık bireysel bir çözüm üretme araşıyışına giriştim ve kendim için 24'lük ızgara mantığı ile yeni bir yapı ürettim. Üstelik bunu varsayılan Bootstrap class'larının üzerine bastırarak uyguladım. Şu anki aşamada ilk olarak kendi blog sayfamda kullanıyorum ancak ufak denemelerim sonucunda biraz daha bunu genişleterek 32 veya 54'e çıkarabilirim diye düşünüyorum. Ayrıca blog sayfamın Content alanının genişliğini de bir nebze olsun genişleterek şimdiden kendi ızgaram ile kendi görünümümü özelleştirebildim. 

24'lük Izgara CSS Kodu

Uygulamış olduğum 24 lük grid CSS'ini minify olarak alabilirsiniz. İlerde daha detaylı olarak Github üzerinden yayınlamayı düşünüyorum.

*{box-sizing:border-box}body{margin:0}[class^=col]{flex-shrink:0;padding-left:17px;padding-right:17px}.col-1{flex-basis:4.166666667%;max-width:4.166666667%}.col-2{flex-basis:8.333333334%;max-width:8.333333334%}.col-3{flex-basis:12.500000001%;max-width:12.500000001%}.col-4{flex-basis:16.666666668%;max-width:16.666666668%}.col-5{flex-basis:20.833333335%;max-width:20.833333335%}.col-6{flex-basis:25%;max-width:25%}.col-7{flex-basis:29.166666667%;max-width:29.166666667%}.col-8{flex-basis:33.333333334%;max-width:33.333333334%}.col-9{flex-basis:37.500000001%;max-width:37.500000001%}.col-10{flex-basis:41.666666668%;max-width:41.666666668%}.col-11{flex-basis:45.833333335%;max-width:45.833333335%}.col-12{flex-basis:50%;max-width:50%}.col-13{flex-basis:54.166666667%;max-width:54.166666667%}.col-14{flex-basis:58.333333334%;max-width:58.333333334%}.col-15{flex-basis:62.500000001%;max-width:62.500000001%}.col-16{flex-basis:66.666666668%;max-width:66.666666668%}.col-17{flex-basis:70.833333335%;max-width:70.833333335%}.col-18{flex-basis:75%;max-width:75%}.col-19{flex-basis:79.166666667%;max-width:79.166666667%}.col-20{flex-basis:83.333333334%;max-width:83.333333334%}.col-21{flex-basis:87.500000001%;max-width:87.500000001%}.col-22{flex-basis:91.666666668%;max-width:91.666666668%}.col-23{flex-basis:95.833333335%;max-width:95.833333335%}.col-24{flex-basis:100%;max-width:100%}.container{margin-left:auto;margin-right:auto}.row{display:flex;flex-wrap:wrap}@media screen and (min-width:768px){.container{max-width:720px}.col-sm-1{flex-basis:4.166666667%;max-width:4.166666667%}.col-sm-2{flex-basis:8.333333334%;max-width:8.333333334%}.col-sm-3{flex-basis:12.500000001%;max-width:12.500000001%}.col-sm-4{flex-basis:16.666666668%;max-width:16.666666668%}.col-sm-5{flex-basis:20.833333335%;max-width:20.833333335%}.col-sm-6{flex-basis:25%;max-width:25%}.col-sm-7{flex-basis:29.166666667%;max-width:29.166666667%}.col-sm-8{flex-basis:33.333333334%;max-width:33.333333334%}.col-sm-9{flex-basis:37.500000001%;max-width:37.500000001%}.col-sm-10{flex-basis:41.666666668%;max-width:41.666666668%}.col-sm-11{flex-basis:45.833333335%;max-width:45.833333335%}.col-sm-12{flex-basis:50%;max-width:50%}.col-sm-13{flex-basis:54.166666667%;max-width:54.166666667%}.col-sm-14{flex-basis:58.333333334%;max-width:58.333333334%}.col-sm-15{flex-basis:62.500000001%;max-width:62.500000001%}.col-sm-16{flex-basis:66.666666668%;max-width:66.666666668%}.col-sm-17{flex-basis:70.833333335%;max-width:70.833333335%}.col-sm-18{flex-basis:75%;max-width:75%}.col-sm-19{flex-basis:79.166666667%;max-width:79.166666667%}.col-sm-20{flex-basis:83.333333334%;max-width:83.333333334%}.col-sm-21{flex-basis:87.500000001%;max-width:87.500000001%}.col-sm-22{flex-basis:91.666666668%;max-width:91.666666668%}.col-sm-23{flex-basis:95.833333335%;max-width:95.833333335%}.col-sm-24{flex-basis:100%;max-width:100%}}@media screen and (min-width:1024px){.container{max-width:960px}.col-md-1{flex-basis:4.166666667%;max-width:4.166666667%}.col-md-2{flex-basis:8.333333334%;max-width:8.333333334%}.col-md-3{flex-basis:12.500000001%;max-width:12.500000001%}.col-md-4{flex-basis:16.666666668%;max-width:16.666666668%}.col-md-5{flex-basis:20.833333335%;max-width:20.833333335%}.col-md-6{flex-basis:25%;max-width:25%}.col-md-7{flex-basis:29.166666667%;max-width:29.166666667%}.col-md-8{flex-basis:33.333333334%;max-width:33.333333334%}.col-md-9{flex-basis:37.500000001%;max-width:37.500000001%}.col-md-10{flex-basis:41.666666668%;max-width:41.666666668%}.col-md-11{flex-basis:45.833333335%;max-width:45.833333335%}.col-md-12{flex-basis:50%;max-width:50%}.col-md-13{flex-basis:54.166666667%;max-width:54.166666667%}.col-md-14{flex-basis:58.333333334%;max-width:58.333333334%}.col-md-15{flex-basis:62.500000001%;max-width:62.500000001%}.col-md-16{flex-basis:66.666666668%;max-width:66.666666668%}.col-md-17{flex-basis:70.833333335%;max-width:70.833333335%}.col-md-18{flex-basis:75%;max-width:75%}.col-md-19{flex-basis:79.166666667%;max-width:79.166666667%}.col-md-20{flex-basis:83.333333334%;max-width:83.333333334%}.col-md-21{flex-basis:87.500000001%;max-width:87.500000001%}.col-md-22{flex-basis:91.666666668%;max-width:91.666666668%}.col-md-23{flex-basis:95.833333335%;max-width:95.833333335%}.col-md-24{flex-basis:100%;max-width:100%}}@media screen and (min-width:1216px){.container{max-width:1152px}.col-lg-1{flex-basis:4.166666667%;max-width:4.166666667%}.col-lg-2{flex-basis:8.333333334%;max-width:8.333333334%}.col-lg-3{flex-basis:12.500000001%;max-width:12.500000001%}.col-lg-4{flex-basis:16.666666668%;max-width:16.666666668%}.col-lg-5{flex-basis:20.833333335%;max-width:20.833333335%}.col-lg-6{flex-basis:25%;max-width:25%}.col-lg-7{flex-basis:29.166666667%;max-width:29.166666667%}.col-lg-8{flex-basis:33.333333334%;max-width:33.333333334%}.col-lg-9{flex-basis:37.500000001%;max-width:37.500000001%}.col-lg-10{flex-basis:41.666666668%;max-width:41.666666668%}.col-lg-11{flex-basis:45.833333335%;max-width:45.833333335%}.col-lg-12{flex-basis:50%;max-width:50%}.col-lg-13{flex-basis:54.166666667%;max-width:54.166666667%}.col-lg-14{flex-basis:58.333333334%;max-width:58.333333334%}.col-lg-15{flex-basis:62.500000001%;max-width:62.500000001%}.col-lg-16{flex-basis:66.666666668%;max-width:66.666666668%}.col-lg-17{flex-basis:70.833333335%;max-width:70.833333335%}.col-lg-18{flex-basis:75%;max-width:75%}.col-lg-19{flex-basis:79.166666667%;max-width:79.166666667%}.col-lg-20{flex-basis:83.333333334%;max-width:83.333333334%}.col-lg-21{flex-basis:87.500000001%;max-width:87.500000001%}.col-lg-22{flex-basis:91.666666668%;max-width:91.666666668%}.col-lg-23{flex-basis:95.833333335%;max-width:95.833333335%}.col-lg-24{flex-basis:100%;max-width:100%}}@media screen and (min-width:1408px){.container{max-width:1344px}.col-xl-1{flex-basis:4.166666667%;max-width:4.166666667%}.col-xl-2{flex-basis:8.333333334%;max-width:8.333333334%}.col-xl-3{flex-basis:12.500000001%;max-width:12.500000001%}.col-xl-4{flex-basis:16.666666668%;max-width:16.666666668%}.col-xl-5{flex-basis:20.833333335%;max-width:20.833333335%}.col-xl-6{flex-basis:25%;max-width:25%}.col-xl-7{flex-basis:29.166666667%;max-width:29.166666667%}.col-xl-8{flex-basis:33.333333334%;max-width:33.333333334%}.col-xl-9{flex-basis:37.500000001%;max-width:37.500000001%}.col-xl-10{flex-basis:41.666666668%;max-width:41.666666668%}.col-xl-11{flex-basis:45.833333335%;max-width:45.833333335%}.col-xl-12{flex-basis:50%;max-width:50%}.col-xl-13{flex-basis:54.166666667%;max-width:54.166666667%}.col-xl-14{flex-basis:58.333333334%;max-width:58.333333334%}.col-xl-15{flex-basis:62.500000001%;max-width:62.500000001%}.col-xl-16{flex-basis:66.666666668%;max-width:66.666666668%}.col-xl-17{flex-basis:70.833333335%;max-width:70.833333335%}.col-xl-18{flex-basis:75%;max-width:75%}.col-xl-19{flex-basis:79.166666667%;max-width:79.166666667%}.col-xl-20{flex-basis:83.333333334%;max-width:83.333333334%}.col-xl-21{flex-basis:87.500000001%;max-width:87.500000001%}.col-xl-22{flex-basis:91.666666668%;max-width:91.666666668%}.col-xl-23{flex-basis:95.833333335%;max-width:95.833333335%}.col-xl-24{flex-basis:100%;max-width:100%}}

İlerleyen zamanlarda nasıl düşünürüm bilmiyorum ancak muhtemelen bu gidişle bu yapının çok daha dışına çıkabilirim diye düşünüyorum. Zaman ayırdığınız için teşekkürler.

Vuex Store - Mutations ve Vue.js Reaktivitesi


Mutasyonların Vue'nun Reaktivite Kurallarına Uyması

Bir Vuex mağazasının state'i Vue tarafından reaktif hale getirildiğinden, state üzerinde değişiklik yaptığınızda durumu gözlemleyen Vue bileşenleri otomatik olarak güncellenecektir. Bu aynı zamanda Vuex mutasyonlarının düz Vue ile çalışırken aynı reaktivite uyarılarına tabi olduğu anlamına gelir. 

Yani CLI üzerinden değil de, web üzerinde kullanmış olduğunuz Vue örneği ile Store üzerinde commit işlemi yapacağınız zaman karşınıza Vue'nun reaktivitesi sorunu çıkacaktır. Değişim yaptığınız veri ile değişen verileriniz birbirleri ile reaktif bir şekilde çalışacağından iki veri arasında bir bağ kurulmuş olacak ve siz store üzerinde değişiklik yapmadığınız halde değişim yapmış olduğunuz veri üzerinde değişiklik yaptığınızda Store üzerindeki veri de bundan etkilenecektir. Aşağıdaki örnekleri inceleyelim.


state: {
    user: {
      id: 1
    }
},

Yukarıdaki user'a bir mutation uygulayalım.


mutations: {
    setUserName (state, userData) {
        // userData = {
        //     id: 2,
        //     name: Ali
        //}
        state.user = userData;
}

Yukarıda gördüğünüz gibi "userData"yı direk "user"a mutate ettik. Şimdi "userData" yı bir Vue bileşeni içerisinde "userData.name = Veli" yaparsak, Store üzerindeki "user.name" de değişmiş olacak. Bu yüzden aşağıdaki yöntemler ile bu sorunu aşmanız gerekir.

state: {
    user: {
      id: 1
    }
  },
  getters: {
    getUserId: state => state.user.id,
    getUserName: state => state.user.name
  },
  mutations: {
    setUserName (state, name) {
      // İlk çözüm:
      // user üzerinde değeri önceden belirtin örn: user.name = null ve şöyle görünmeli
      // user: {
      //     id: 2,
      //     name: null
      // }
      // Böylelikle "name" daha önceden belirtildiği için Vue içerisindeki değişiklik
      // burayı tetiklemeyecek
      state.user.name = name

      // İkinci çözüm:
      // Object assign methodu ile her iki verinin de referansını sıfırlayın
      // Object.assign({}, state.user, { name })
      state.user = { ...state.user, name }

      // Üçüncü çözüm:
      // Vue'nun kendi içerisindeki Vue.set() fonksiyonunu kullanın.
      // Aynı sonucu verecektir.
      Vue.set(state.user, 'name', name)
}

Vue'nun reaktivitesinin Mutations üzerindeki etkisini ve bunun bir sorunken üç farklı yol ile çözümüne değindik. Tekrar hatırlatmakta fayda var bu sorun tam olarak düz Vue kullanırken karşılaşabileceğiniz bir durum. CLI üzerinde böyle bir sorun yaşamayacaksınız. Bir sonraki yazımda Mutatitonsların sabitler ile kullanımına değineceğiz. Teşekkürler.

Vuex Store - Mutations Kavramı ve Anlatımı


Bir Vuex mağazasında State üzerindeki veriyi değiştirmenin tek yolu bir mutasyon gerçekleştirmektir. Mutasyon içerisinde bir fonksiyon oluşturduğumuzda State'i ilk argüman olarak alır:


const store = new Vuex.Store({
  state: {
    miktar: 1
  },
  mutations: {
    artir (state) {
      // State üzerindeki "miktar"ı güncelle
      state.miktar++
    }
  }
})

Bir mutasyonu doğrudan nesne adı ile çağıramazsınız. Bunun için store.commit("") fonksiyonunu çağırmanız gerekir.


store.commit('miktar')

Veriyi Commit Etmek

Store.commit'e payload(güncelleyeceğiniz veri) olarak adlandırılan ek bir bağımsız değişken iletebilirsiniz:


mutations: {
  increment (state, payload) {
    state.miktar += payload.sayi
  }
}

Payload güncel olarak değişim yapacağınız data'dır.


store.commit('artir', {
  sayi: 10
})

Nesne Tarzında Commit Yapmak

Bir mutasyonu gerçekleştirmenin alternatif bir yolu, type özelliği olan bir nesneyi doğrudan kullanmaktır:


store.commit({
  type: 'artir',
  sayi: 10
})

Yukarıda commit() içerisine sadece bir nesne ekledik ve daha önce birinci parametrede belirttiğimiz mutasyon adını bu sefer type değeri ile ekledik. Vuex de adı type üzerinden aldı. Bu durum mutasyonun daha önceki yapısı üzerinde de bir değişiklik yapmanızı gerektirmez. Yani aynı işlemi yapmış olduk.

Mutasyonların nasıl işlediğine ve kullanıldığına değindik. Mutasyon kullanımını üç farklı makalede ele alacağız. Bir sonrakinde Vue'nun reaktivite sisteminin Mutasyonlar üzerindeki etkisini inceleyeceğiz.

Vuex Store - Getters Kavramı ve Anlatımı


Bazen, örneğin bir öğe listesini filtrelemek ve onları saymak gibi, duruma göre çıktısını istediğiniz bir veriyi ayrıca hesaplamamız gerekebilir.


computed: {
  gorevListesi() {
    return this.$store.state.gorevler.filter(
      (gorev) => gorev.bitisDurumu === true
    ).length;
  },
}

Birden fazla alanla bunu kullanmak istiyorsak, ya bu işlevi çoğaltmamız lazım ya da ayrı bir dosyaya ekleyip her ihtiyacımız olduğunda bu dosyayı ilgili component içerisinde import etmemiz gerekir. İki seçenek te düzenli kodlama mantığından biraz uzak.

Vuex Store bu işlevleri Getters üzerinden tanımlamanıza olanak tanır. Bu işlevleri Vue örneğindeki computed'lar üzerinde tanımladığımız işlevler gibi de düşünebilirsiniz. Computed'lar da Getters'lar gibi bağımlılıklarına göre önbelleğe alınır ve sadece belirli bağımlılıklar değiştirildiğinde yeniden işlevsel olarak hesaplamaya dahil edilir.  

Getters Tanımlamak

Bir Getters tanımlamak istediğinizde, state'i ilk parametresinden alabilirsiniz.


const store = new Vuex.Store({
  state: {
    gorevler: [
      { id: 1, baslik: '...', bitisDurumu: true },
      { id: 2, baslik: '...', bitisDurumu: false }
    ]
  },
  getters: {
    tamamlanmisGorevler: state => {
      return state.gorevler.filter(gorev => gorev.bitisDurumu)
    }
  }
})

Getters'a State Gibi Erişmek

Bir Getters'a "store.getters" üzerinden erişebilirsiniz ve direk nesne öğesi olarak alabilirsiniz.


store.getters.tamamlanmisGorevler

Ayrıca Getters içerisine diğer Getters işlevlerini de alabilirsiniz. İkinci değer olarak da Getters'lara erişebilirsiniz.


getters: {
  // ...
  bitmisGorevlerinSayisi: (state, getters) => {
    return getters.tamamlanmisGorevler.length
  }
}

Daha önce tanımlamış olduğumuz "tamamlanmisGorevler" adlı getters'ı yeni bir getters olan "bitmisGorevlerinSayisi" içerisinde kullandık.

Getters'ın Component İçerisinde Kullanımı

Artık onu herhangi bir component içerisinde kullanabiliriz.


computed: {
  bitmisGorevler () {
    return this.$store.getters.tamamlanmisGorevler
  }
}

Not: Getters'ların Vue'nun reaktivite sistemine dahil olduğunu unutmayın.

Method'a Farklı Bir Erişme Biçimi

Getters'lara bir fonksiyon üzerinden argüman da iletebilirsiniz. Bu işlem mağazada bir diziyi sorgulamak istediğinizde kullanışlıdır.


getters: {
  // ...
  gorevGetir: (state) => (id) => {
    return state.gorevler.find(gorev => gorev.id === id)
  }
}


store.getters.gorevGetir(2) // -> { id: 2, baslik: '...', tamamlanmis: false }

Yukarıdaki işlem ile "id" üzerinden herhangi bir gorev'i alabiliyoruz.

Getters'lar ile ilgili makalenin sonuna geldik. Bir sonraki yazımda görüşmek üzere.

.map dosyaları nedir, ne işe yarar ?


Web sayfanıza bir Javascript kütüphanesi eklediğinizde aşağıdaki gibi bir uyarıyı gözlemleyebilirsiniz. Çünkü sizden .min.x.js eklemesi yaptığınızda sonu .map uzantılı bir dosya isteyecektir.

Web üzerinde .map dosyaları Javascript, CSS ve Typescript dosyaları için kullanılmaktadır. Bu dosyalar kaynak haritaları olarak adlandırılırlar. Peki ne amaçla kullanılmaktadırlar.

Angular.js gibi bir kütüphane dosyasını minify ettiğinizde, elinizdeki düzenli kodu verip yerine okunamayacak biçimde yani sözdeyimi çirkin hale getirilmiş boşluklarından arındırılmış biçimini alırsınız. Uygulamanız üretim modunda yani projenin sunum halinde bir hata oluştuğunda kaynak haritası minify edilmiş dosyanızı otomatik olarak alacak ve kodun orjinal sürümünü görmenize izin verecektir. Bunu görmek için bir örnek uygulamakta fayda var.

.map Dosyasını Kullanmak

Örnek vermek gerekirse sitemizde Bootstrap kullanıyor olalım. Bootstrap içerisinde bootstrap.min.js ve bootstrap.min.js.map dosyalarını dist/js içerisinden site dizinimize atalım. İndirdiğiniz arşiv içerisindeki js/src altındaki dosyaları site dizininizde bir /maps klasörü oluşturun ve içerisine atın. Ardından .map dosyanızı editörde açın ve içerisindeki "../../js/src/" kaynak yollarının hepsini oluşturduğunuz /maps dizini yolu ile değiştirin.

Şimdi bootstrap.min.js dosyamızı <script> etiketi ile çağıralım. Siteyi açtığınızda Console altında .map dosyası için bir hata ile karşılaşmayacaksınız çünkü tarayıcı .min.js ile aynı dizinde olan .map dosyasını otomatik olarak tespit edecektir.

Ardından Geliştirici Araçlarının,  Sources panelinden bootstrap.min.js dosyasını bulup açtığınızda dosya içerisinde şöyle bir uyarı ile karşılaşacaksınız.

"Source Map detected". Yani .map dosyası tespit edildi. Bu uyarıyı gördüğünüze göre şimdi Ctrl+P ile dosya denetleyicisi penceresini açın ve oradan bir Bootstrap dosyası olan modal.js dosyasını açın. Dosyayı açtığınızda artık debug yapmak istediğinizde, buradan sorunun tam olarak nerede olduğunu dosyanın orjinali üzerinden tespit edebileceksiniz.

Aynı durum CSS için de geçerlidir. SASS ve SCSS dosyalarımızın kaynak haritasını da çıkartarak bu işlemi uygulayabiliriz.

Bir geliştirici bu işlemi nasıl uygulayabilir ?

Bir üretim uygulamasında hata ayıklamak için kullanırsınız. Geliştirme modunda, Angular'ın tam sürümünü kullanabilirsiniz. Üretimde, minify edilmiş sürümü kullanırsınız.

Kaynak haritası kullanmak zorunda mıyım ?

Üretim kodunda daha kolay hata ayıklamayı önemsiyorsanız, evet, yapmalısınız.

Map dosyası ile ilgili açıklamalar bu kadardı, bir sonraki makalede görüşmek üzere.

Vuex Store - State Kavramı ve Anlatımı


Daha önce Vuex Store'a bir giriş yapmış ve bir Vuex Store örneğini incelemiştik. Oradaki dört bölümden kısaca bahsetmiştik. Bunlar State, Getters, Mutations ve Actions'tı.

State Management Pattern

Vuex bir State Management Pattern yani bunu çevirmeyeceğim ama şöyle söyleyeyim Veri yönetimi kütüphanesidir. Bir devlet düşünün çatısı altında her şey yönetilir, işte State burada devlet konumundadır ve aynı zamanda hem uygulama içerisindeki veriyi hem de kendi kendini yöneten anlamına gelmektedir.

State kavramını anladığımıza göre Vuex'in işlevine geçelim. Vuex tam olarak veriyi veya verileri istediğiniz bir biçimde merkezi bir yapı içerisinde yönetmenizi sağlar. Yani kısaca tüm uygulama içerisinde bir merkezi depo görevi görür. State kavramını yukarıda açıklamıştım. Şimdi tam olarak çalışma sisteminden bahsedeceğim.


import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    isim: "Gokhan"
  },
  mutations: {
    ismiDegistir (state, data) {
      state.isim = data
    }
  }
})

Yukarıdaki bizim Vuex örneğimiz. Şimdi herhangi bir component içerisinde State'deki isim değerini alalım.

State Verisine Erişim


computed: {
  isim() {
    return this.$store.state.isim
  }    
}

Bildiğiniz gibi computed özelliği Vue'nun reaktivitesine dahil olmadığı için tekrar tekrar hesaplamaya dahil edilmiyor. Store içerisinden veriyi almak için de computed kullanılıyor. Çünkü set/get mantığıyla değil sadece get mantığı ile çalışıyor. Artık "isim" adında bir datamız var ve istediğimiz şekilde kullanabiliriz.

State Verisi Üzerine Değişim Uygulama

Önceki yayında mutationsların state üzerindeki veriyi değiştirmek yani mutasyona uğratmak için kullanıldığından bahsetmiştim. "ismiDegistir" adında bir mutations'ımız var. Şimdi state.isim'e yeni bir değer atayalım. Bunun için Vue örneği içerisinde daima this.$store.commit() fonksiyonunu kullanacağız.


methods: {
  yeniIsim(isim) {
    this.$store.commit('ismiDegistir', isim);
  }
}

Fonksiyon adları karışmasın diye method adını "yeniIsim" olarak kullandım. this.yeniIsim("Adınız") biçiminde artık Store üzerindeki veriyi değiştirebilirsiniz.

 

State üzerindeki verinin nasıl alındığını ve mutasyona uğratıldığını anlattım. Bir sonraki yazımda da Getters özelliğine geçeceğiz. 

Polyfill nedir, ne için kullanılır ?


Web platformu üzerindeki ilerleyen zamanlarınızda karşınıza Polyfill adında bir kavram çıktı. Nedir bu Polyfill ve ne demektir ?

PolyFill Kavramı

Polyfill, kısaca tanımlamak gerekirse yazmış olduğunuz kodlarınızın eski tarayıcılarda da çalışmasını sağlamak için ayrıca üretmiş olduğunuz destekleyici yazılımlara denir.

Tüm dünyada kullanılan birçok farklı tarayıcı ve tarayıcı sürümü vardır, her biri diğerlerinden biraz farklı özelliklere sahiptir. Bu, tarayıcılar için geliştirmeyi zor bir görev haline getirebilir. Popüler tarayıcıların en son sürümleri, eski tarayıcıların yapamadığı birçok şeyi yapabilir ancak yine de eski tarayıcıları desteklemeniz gerekebilir. Polyfill'ler, eksik özellikleri çoklu dolgularla yeniden oluşturmaya çalışarak farklı tarayıcıları desteklemeyi kolaylaştırır: Bunları destekleyen tarayıcılarda ve desteklemeyen tarayıcılarda en yeni ve en iyi özelliklerden yararlanabilirsiniz.

Mesela güncel tarayıcıların kullandığı Javascript Promise'ı düşünün.


Yukarıdaki caniuse.com/promises çıktısına baktığınız zaman Pormise'ların IE 6'dan 11'e kadar desteklemediği görürsünüz. Promise için ES6(Ecma Script 6) kullanmanız gerekmekte. İşte tam olarak burada Polyfill'ler devreye girmektedir. 
Ya sizin bunu kendinizin ek olarak bir kütüphane hazırlamanız ya da Promise örneği gibi bilinen bir özellik ise dışarıdan bir kütüphane ile bunu sağlamanız gerekir. Ancak eğer eski tarayıcılarla ilgili böyle bir sorununuz varsa.

Tabi ki bu durum yalnızca Javascript tarafında karşılaşılan bir durum değil. Ne demiştik, güncel tarayıcılar ve güncel olmayan tarayıcılar arasındaki farklılık. Bu yüzden aynı durum HTML ve CSS için de geçerli. 

Neler Kullanabiliriz ?

Aşağıda Polyfill için yardımcı olabilecek araçların bir listesi oluşturulmuş. Bu liste Modernizr projesi içerisinde bulunuyor. Evet, daha önce Modernizr ile karşılaştıysanız bu kütüphane de aslında Polyfill sağlıyor.

HTML5 Cross Browser Polyfills



Modernizr'ı da ayrıca vermek gerekirse:

Modernizr.com


Bununla beraber Polyfill.io adında yine web üzerinde aynı desteği sağlayan farklı bir kütüphane de bulunuyor. Ulaşmak için:

Polyfill.io



Vuex Store - Giriş ve Konu Anlatımı


Vue.js ile beraber Vuex'e girmeye karar verdiyseniz yada ne olduğunu merak ediyorsanız, buradan itibaren temiz bir giriş yapacağız. Temelden derinlere doğru inerek Vuex içerisindeki tüm konulara ve alanlara değinmek istiyorum. Hazırsanız başlayalım.

Vuex Kullanım Amacı

Vue.js de dikkat ettiyseniz component yapısı içerisinde veriyi içerden dışarıya, yani alt component'ten üst component'e göndermek zor ve karmaşık bir durum. Ayrıca verinin alt component'te sürekli değişimini ve bunun gibi onlarca component olduğunu düşünün.

Tam olarak burada Vuex veriyi merkezi bir yerde birleştirip tüm component'ler arasında paylaşmayı ve daha dinamik bir yapıyı sağlamayı amaçlıyor. 

Vuex Kullanımına Giriş

Kurulumdan bahsetmeyeceğim, yeni bir Vue örneği ile beraber gelen seçenekler arasında direk kurabiliyorsunuz veya vâr olan bir projeye dahil etmek istiyorsanız netten dökümantasyon incelemek durumundasınız.

Vuex projenizde kuruysa veya kurduysanız ilk olarak /store dizinindeki index.js'i inceleyelim.

import Vue from 'vue' 
import Vuex from 'vuex'

Vue.use(Vuex) 

const store = new Vuex.Store({ 
  state: { 
    count: 0 
  },
  getters: {
  
  }   
  mutations: { 
    increment (state) { 
      state.count++ 
    } 
  },
  actions: {

  }
})

Burada gördüğünüz üzere bir Vuex Store nesnesi oluşturulmuş gözükmekte. Bölümleri şu şekilde.

State: Store verilerinin tutulduğu alan. Store'a ait tüm veriler State içerisinde barındırılır. Yani kaynak burasıdır.

Getters: State içerisindeki veriyi hem direk State üzerinden hem de buradan alabilirsiniz. Ancak Getters'ın farkı veriye mesela "State.kullanicilar.map( ... return x ...)" gibi bir değişiklik yaparak çıktı almak istediğiniz durumlarda kullanılır.

Mutations: State üzerindeki bir veriyi güncellemek istediğiniz zaman Mutations'ları kullanıyoruz. Yani bu demek oluyor ki State üzerindeki veriyi doğrudan değiştiremezsiniz.

Actions: Bazen çok daha detaylı işlemler yapmanız gerekir, mesela form isteği atıp gelen veriyi işlemek gibi. Bunun için Mutations değil Actions'ları kullanırsınız. Sonra veriyi yine değiştirmek için Actions üzerindeki işleminiz bitince, yine Actions içerisinde Mutations'ları çağırır veri güncellemeyi aynı metot ile yaparsınız.


Bu yazımda inceleyeceklerimiz bu kadardı. Bir sonraki yazımda Vuex Store üzerindeki State özelliğine değineceğiz. Teşekkürler.