Bir Front-End Geliştiricinin Maceraları — Web Performansını iyileştirme çalışmalarımız
Heybooster’da Front-End Developer olarak işe başladığımda, product ownerimiz aşağıdaki sorunları çözmemi istedi:
- Kullanıcılardan sıkça dönüş aldığımız sayfa hızı sorunlarının çözümüne öncülük etmem,
- Şu andaki yapıdaki bugların çözülmesi ile birlikte yeni tasarımların da %99 oranında aynı şekilde ve responsive şekilde geçirilmesi,
- Sitedeki tüm userflowları cover ettiğimize emin olmak,
Ben de Heybooster’i iyileştirmek, geliştirmek ve ilerletmek için elimden gelenin en iyisini yapmaya karar verip çalışmaya başladım.
Bu blog yazısında anlattığım çalışmalar genel olarak Front-End tarafındaki geliştirmeleri ve iyileştirmeleri kapsamaktadır.
Gereksiz veya kullanılmayan paketlerin ve componentlerin kaldırılması
- Projemizde kurulu plan npm paketlerini incelediğimde bazı paketlerin kurulu olmasına rağmen proje içerisinde hiç kullanılmadığını gördüm ve bu npm paketlerini kaldırdım.
- Proje içerisinde çok basit işlemler için bile npm paketinin kurulduğunu ve bu paketlerin beraberinde gereksiz yükler getirdiğini ve aslında bir npm paketi kullanmadan da sorunlarımızı çözebileceğimi farkettim.Bu npm paketlerinin hepsini kaldırarak kendi componentlerimizi ve javascript methodlarımızı yazdım.
- Projenin geliştirilmesi ile birlikte bazı componentler artık kullanılmıyordu. Fakat yine de bu componentler import edilmeye devam ediliyordu. Kod incelemesi yaparak kullanmadığımız bu componentleri sildim.
Büyük boyutlu paketlerin değiştirilmesi
Line chart ve Treemap chart grafiklerini ve Grid tablosunu kullanmak için syncfusion’un geliştirdiği paketleri kullanıyorduk.Fakat bu paketlerin boyutları çok yüksek olduğu için grafik oluşturulup kullanıcıya gösterilene kadar çok zaman geçmekteydi ve aynı zamanda kötü bir kullanıcı deneyimi oluşturmaktaydı.Bu sorunu çözmek için bu üç kütüphaneyi değiştirmeye karar verdim.
Yeni bir paket seçmeye karar verirken belirlediğimiz kriterler aşağıdaki gibiydi:
- Açık kaynak olması
- Desteklediği özellikler
- Topluluk desteği
- Paket boyutunun küçük olması
- Ücretsiz olması
Yukarıdaki kriterlere göre çeşitli paketleri araştırdım ve deneyerek test ettim.Bizim projemiz için en uygun paketlerden, Line chart için chart.js’i, Grid tablosu için grid.js’i ve Treemap chart için highcharts.js’i kullanmaya karar verdim.
Bu 3 paketi değiştirdikten sonraki boyut değişimleri aşağıdaki grafik gibidir.
Markdown işlemleri için vue-markdown ve vue-simple-markdown iki npm paketi kullanılmaktaydı.bütün markdown işlemleri için tek paket kullanmak için yukarıdaki iki paketi kaldırarak marked.js’yi kurdum.
Tekrarlayan kodların önüne geçmek için mixins ve helpers’lerin kullanılmaya başlanması
Projemizi geliştirirken aynı zamanda code review yaparak kendini tekrarlayan kodlar ile çok sık karşılaşmaktaydım. Daha temiz, yönetilebilir ve optimize kodlar için kendini tekrarlayan kodları mixins ve helperlere çevirdim.
Global olmayan paket, component, prototype ve mixins’lerin ana main.js dosyasından kaldırılması
Ana javascript dosyası main.js içerisinde global olmayan paket, component, prototype ve mixinslerin import edildiğini gördüm ve bu global paket, component, mixinleri sadece gerekli olduğu yerde içeri aktarılıp kullanılabilecek şekilde değiştirdim. Prototyleri de enums olarak localde oluşturdum.
Verileri ve durumları yönetmek için vuex’in kullanılmaya başlanması
Durum yönetimini sağlamak için eventBus kullanmaktaydık. Fakat eventBus projemiz için hiç efektif ve kullanışlı değildi ve kodun okunabilirliğini, yönetimini ve geliştirilmesini zorlaştırıyordu.
Verileri yönetmek için de herhangi global bir yapımız bulunmamaktaydı.
Verileri yönetmek için bir yapının olmaması performance açısından büyük kayıplara yol açıyordu;
- Her sayfa değişikliğinde tekrar tekrar aynı veriyi almak için api istekleri yapılıyordu ve her seferinde api sonucları gelene kadar kullanıcı beklemek zorunda kalıyordu.
- Aynı veri birden fazla yerde kullanılmasına rağmen aynı veriyi elde etmek için farklı yerlerde tekrardan api isteğinde bulunuyordu.
Durum ve verilerin yönetimini sağlayarak web performansını iyileştirmek ve projenin yönetilebilirliğini artırmak için vue js’nin resmi kütüphanesi vuex’i kullanmaya karar verdik. Projenin durumlarını ve verilerini kategorilere ayırmamız gerekeceğini için vuex modüllerini oluşturmam gerekecekti.Vuex modulleri hakkında bilgim olmadığı için test amaçlı bir proje ile vuex modülleri oluşturup kullanarak yapısına hakim oldum.
Şuan vuex modullerini kullanarak projenin veri ve durumlarını kolay bir şekilde yönetebiliyorum.
Code Splitting and Lazy Loading
Bütün viewsler ve componentler tek bir javascript dosyasında toplanmaktaydı.Projedeki component ve views sayısı da büyüdüğü için ana javascript bundle paketinin boyutu çok büyüdü ve sayfa ve componentlerin yüklenme sürelerini kötü etkilemeye başladı.Bu kötü etki de web sayfasının yüklenmesini 30 saniye’ye kadar uzatıyordu.
Bütün component ve views’leri tek bir javascript dosyasında toplamak yerine bunları dinamik olarak yükleyerek parçalarına ayırdım.Böylece bütün yükü dağıtarak ana javascript paketinin boyutunu küçülttük.
Sayfayı yenilemeden verileri değiştirme
Heybooster client bazlı çalışan bir projedir. Kullanıcının her client değiştirdiğinde o cliente ait verilerin yüklenmesi için sayfa yenileniyordu.Her sayfa yenilendiğinde bütün javascript ve resim dosyaları yeniden yüklenmesi performanse kaybına sebep olmaktaydı. ayrıca bazı apiler kullanıcı bazında çalıştığı için tekrardan yüklenmesi gereksizdi.Bu durum vue’nin yapısına da uygun olmayan yanlış geliştirilmiş bir özellikti.
Bu sorunu çözmek aşağıdaki adımları izledik.
- Client değiştirildiğinde, bir cliente ait bütün bütün vuex verilerini temizledim.
- Client’e göre çalışan bütün api isteklerini tekrarlatarak api isteklerini yeniden isteklerde bulundum.
Cache sorunlarının çözülmesi
Her deployment sonrası yaşadığımız en büyük problem cachelerin temizlenmesi ile ilgiliydi. Tarayıcı javascript dosyasını indirdikten sonra disk cache’sine kaydediyordu.Performance açısından baktığımızda web sayfasının daha hızlı yüklenmesi için iyi bir durum fakat yeni geliştirmelerin canlıya alınmasında sorunlar yaşıyorduk.
Her deployment sonrası cache’yi silme ilgili sorunları çözmek için aşağıdaki yöntemleri denedim:
- Webpack ile javascript dosyalarının isimlerini dynamic hale getirerek hep deployment sonrası cache’yi bozma: Bu çözümün uygulanması için her deployment sonrası kullanıcının sayfayı yenilemesi gerekiyordu. Çünkü eski bundle dosyaları silinerek içeriğe göre yeni javascript dosyaları oluşturuluyordu.Fakat kullanıcı sayfayı yenilenmeden başka bir sayfaya geçiş yapmak istediğinde “Loading chunk errors” hataları ile karşılaşıyorduk.Çünkü kullanıcı hala eski javascript dosyalarını kullanıyordu fakat o javascript dosyaları artık mevcut değil.
- Service worker ile her deployment sonrası kullanıcıya bir uyarı mesajı göstererek yeni sürümün yüklenmesi için sayfayı yeniletmek:Bu çözüm ile de tam olarak istediğimiz gibi çalışmadı.Bu yüzden service worker’i kaldırdık.
Yukarıdaki çözümlerin hiçbiri tam olarak işimizi görmediği için ayarları eski haline getirdik.Front end tarafını amplify’e taşıdıktan sonra amplify’in cache yönetimi ile ilgili bir çözümün olup olmadığını araştırdım ve amplify’in performance modu ile cache sorunumuzu çözebileceğimizi öğrendim. Performance modu’nu ayarladıktan sonra javascript dosyalarımız amplify cdn’si tarafından yönetilmeye başlandı ve her deployment sonrası cachemizi geçersiz kıldı.
Genel olarak web performansımızı iyileştirmek için yaptığım çalışmalardan bahsettim. Yukarıdaki çalışmaların dışında yapabileceğimiz birçok çalışma mevcut. Bunları uyguladıkça ve geliştirdikçe tecrübelerimi aktarmaya devam edeceğim.
Açık kaynak geliştirmelerimi de github adresimde paylaşmaktayım.