Akıllı Paketleme: Eski Kodu Yalnızca Eski Tarayıcılara Nasıl Sunulur

Yayınlanan: 2022-03-10
Kısa özet ↬ Web'de kaynakların etkin bir şekilde gruplandırılması, son zamanlarda büyük ölçüde fikir alışverişinde bulunsa da, kullanıcılarımıza ön uç kaynakları nasıl gönderdiğimiz hemen hemen aynı kaldı. Bir web sitesinin birlikte sunduğu JavaScript ve stil kaynaklarının ortalama ağırlığı artıyor - web sitesini optimize etmek için oluşturma araçları hiç bu kadar iyi olmamıştı. Her zaman yeşil kalan tarayıcıların pazar payı hızla yükselirken ve tarayıcılar adım adım yeni özellikler için destek başlatırken, modern web için varlık dağıtımını yeniden düşünmemizin zamanı geldi mi?

Günümüzde bir web sitesi, trafiğinin büyük bir bölümünü, çoğu ES6+, yeni JavaScript standartları, yeni web platformu API'leri ve CSS öznitelikleri için iyi desteğe sahip, her daim yeşil tarayıcılardan almaktadır. Bununla birlikte, eski tarayıcıların yakın gelecekte hala desteklenmesi gerekiyor - kullanıcı tabanınıza bağlı olarak kullanım payları göz ardı edilemeyecek kadar büyük.

caniuse.com'un kullanım tablosuna hızlı bir bakış, her zaman yeşil kalan tarayıcıların, tarayıcı pazarında aslan payını -% 75'ten fazlasını - işgal ettiğini ortaya koymaktadır. Buna rağmen, norm CSS önekini koymak, tüm JavaScript'imizi ES5'e aktarmak ve önemsediğimiz her kullanıcıyı desteklemek için çoklu dolgular eklemektir.

Bu, tarihsel bağlamda anlaşılabilir olsa da - web her zaman aşamalı geliştirme ile ilgili olmuştur - soru şudur: Azalan bir dizi eski tarayıcıyı desteklemek için kullanıcılarımızın çoğunluğu için web'i mi yavaşlatıyoruz?

ES5'e aktarım, web platformu çoklu dolguları, ES6+ çoklu dolguları, CSS ön eki
Bir web uygulamasının farklı uyumluluk katmanları. (Büyük versiyonu görüntüle)

Eski Tarayıcıları Desteklemenin Maliyeti

Tipik bir derleme işlem hattındaki farklı adımların ön uç kaynaklarımıza nasıl ağırlık ekleyebileceğini anlamaya çalışalım:

ES5'e Aktarma

Aktarmanın bir JavaScript paketine ne kadar ağırlık ekleyebileceğini tahmin etmek için, orijinal olarak ES6+ ile yazılmış birkaç popüler JavaScript kitaplığını aldım ve aktarmadan önce ve sonra paket boyutlarını karşılaştırdım:

Kütüphane Boyut
(küçültülmüş ES6)
Boyut
(küçültülmüş ES5)
Fark
TodoMVC 8,4 KB 11 KB %24.5
sürüklenebilir 53,5 KB 77,9 KB %31.3
luxon 75,4 KB 100,3 KB %24.8
video.js 237.2 KB 335,8 KB %29.4
PixiJS 370.8 KB 452 KB %18

Ortalama olarak, aktarılmamış demetler, ES5'e aktarılmış olanlardan yaklaşık %25 daha küçüktür. ES6+'nın eşdeğer mantığı temsil etmek için daha kompakt ve anlamlı bir yol sağladığı ve bu özelliklerin bazılarının ES5'e aktarılmasının çok fazla kod gerektirebileceği düşünüldüğünde, bu şaşırtıcı değildir.

ES6+ Çoklu Dolgular

Babel, ES6+ kodumuza sözdizimsel dönüşümler uygulama konusunda iyi bir iş çıkarsa da, ES6+'da sunulan Promise , Map ve Set gibi yerleşik özelliklerin ve yeni dizi ve dize yöntemlerinin yine de çoklu doldurulması gerekir. babel-polyfill olduğu gibi bırakmak, küçültülmüş paketinize 90 KB'ye yakın ekleyebilir.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Web Platformu Çoklu Dolgular

Modern web uygulaması geliştirme, çok sayıda yeni tarayıcı API'sinin mevcudiyeti nedeniyle basitleştirilmiştir. Yaygın olarak kullanılanlar, kaynak istemek için fetch , öğelerin görünürlüğünü verimli bir şekilde gözlemlemek için IntersectionObserver ve URL'lerin web'de okunmasını ve değiştirilmesini kolaylaştıran URL belirtimidir.

Bu özelliklerin her biri için spesifikasyonla uyumlu bir çoklu dolgu eklemek, paket boyutu üzerinde fark edilir bir etkiye sahip olabilir.

CSS Ön Eki

Son olarak, CSS ön ekinin etkisine bakalım. Ön ekler, diğer yapı dönüşümlerinin yaptığı gibi paketlere fazla ölü ağırlık eklemeyecek olsa da - özellikle Gzip'd yapıldığında iyi sıkıştırdıkları için - burada hala elde edilecek bazı tasarruflar var.

Kütüphane Boyut
(küçültülmüş, son 5 tarayıcı sürümü için ön ekli)
Boyut
(küçültülmüş, son tarayıcı sürümü için ön ekli)
Fark
Önyükleme 159 KB 132 KB %17
Bulma 184 KB 164 KB %10,9
temel 139 KB 118 KB %15.1
anlamsal kullanıcı arayüzü 622 KB 569 KB %8.5

Efficient Code Gönderimi İçin Pratik Bir Kılavuz

Muhtemelen bununla nereye gittiğim açıktır. Bu uyumluluk katmanlarını yalnızca bunu gerektiren tarayıcılara göndermek için mevcut derleme ardışık düzenlerinden yararlanırsak, eski tarayıcılar için uyumluluğu korurken diğer kullanıcılarımıza - artan bir çoğunluk oluşturanlara - daha hafif bir deneyim sunabiliriz.

Modern paket, bazı uyumluluk katmanlarından vazgeçtiği için eski paketten daha küçüktür.
Demetlerimizi çatallıyoruz. (Büyük versiyonu görüntüle)

Bu fikir tamamen yeni değil. Polyfill.io gibi hizmetler, çalışma zamanında tarayıcı ortamlarını dinamik olarak çoklu doldurma girişimleridir. Ancak bunun gibi yaklaşımların birkaç kusuru vardır:

  • Hizmeti kendiniz barındırıp bakımını yapmadığınız sürece, çoklu dolguların seçimi hizmet tarafından listelenenlerle sınırlıdır.
  • Çoklu doldurma çalışma zamanında gerçekleştiğinden ve bir engelleme işlemi olduğundan, eski tarayıcılardaki kullanıcılar için sayfa yükleme süresi önemli ölçüde daha yüksek olabilir.
  • Her kullanıcıya ısmarlama bir çoklu dolgu dosyası sunmak, sisteme entropi getirir, bu da işler ters gittiğinde sorun gidermeyi zorlaştırır.

Ayrıca, bu, bazen çoklu dolguların kendisinden daha büyük olabilen uygulama kodunun aktarılmasıyla eklenen ağırlık sorununu çözmez.

Şimdiye kadar tanımladığımız tüm şişkinlik kaynaklarını nasıl çözebileceğimize bakalım.

İhtiyacımız Olan Araçlar

  • Web paketi
    Bu bizim oluşturma aracımız olacak, ancak süreç Parsel ve Toplama gibi diğer oluşturma araçlarına benzer kalacak.
  • tarayıcı listesi
    Bununla, desteklemek istediğimiz tarayıcıları yöneteceğiz ve tanımlayacağız.
  • Ve bazı Browserslist destek eklentilerini kullanacağız.

1. Modern ve Eski Tarayıcıları Tanımlama

İlk olarak, "modern" ve "eski" tarayıcılarla ne demek istediğimizi açıklığa kavuşturmak istiyoruz. Bakım ve test kolaylığı için, tarayıcıları iki ayrı gruba ayırmaya yardımcı olur: çok az çoklu doldurma veya aktarma gerektirmeyen tarayıcıları modern listemize eklemek ve geri kalanını eski listemize koymak.

Firefox >= 53; Kenar >= 15; Krom >= 58; iOS >= 10.1
ES6+'yı, yeni CSS özelliklerini ve Promises ve Fetch gibi tarayıcı API'lerini destekleyen tarayıcılar. (Büyük versiyonu görüntüle)

Projenizin kökündeki bir Tarayıcı listesi yapılandırması bu bilgileri saklayabilir. "Ortam" alt bölümleri, aşağıdaki gibi iki tarayıcı grubunu belgelemek için kullanılabilir:

 [modern] Firefox >= 53 Edge >= 15 Chrome >= 58 iOS >= 10.1 [legacy] > 1%

Burada verilen liste sadece bir örnektir ve web sitenizin gereksinimlerine ve mevcut zamana göre özelleştirilebilir ve güncellenebilir. Bu yapılandırma, daha sonra oluşturacağımız iki ön uç paketi grubu için gerçeğin kaynağı görevi görecek: biri modern tarayıcılar için, diğeri tüm diğer kullanıcılar için.

2. ES6+ Aktarma ve Çoklu Doldurma

JavaScript'imizi çevreye duyarlı bir şekilde aktarmak için babel-preset-env kullanacağız.

Şununla projemizin kökündeki bir .babelrc dosyasını başlatalım:

 { "presets": [ ["env", { "useBuiltIns": "entry"}] ] }

useBuiltIns bayrağının etkinleştirilmesi, Babel'in ES6+'nın bir parçası olarak tanıtılan yerleşik özellikleri seçici olarak çoklu doldurmasına olanak tanır. Polyfillleri yalnızca çevrenin gerektirdiği olanları içerecek şekilde filtrelediği için, babel-polyfill ile nakliye maliyetini tamamen azaltıyoruz.

Bu bayrağın çalışması için, giriş noktamızda babel-polyfill de içe aktarmamız gerekecek.

 // In import "babel-polyfill";

Bunu yapmak, büyük babel-polyfill içe aktarmayı, hedeflediğimiz tarayıcı ortamı tarafından filtrelenen ayrıntılı içe aktarmalarla değiştirecektir.

 // Transformed output import "core-js/modules/es7.string.pad-start"; import "core-js/modules/es7.string.pad-end"; import "core-js/modules/web.timers"; …

3. Polyfilling Web Platformu Özellikleri

Web platformu özellikleri için çoklu dolguları kullanıcılarımıza göndermek için her iki ortam için iki giriş noktası oluşturmamız gerekecek:

 require('whatwg-fetch'); require('es6-promise').polyfill(); // … other polyfills

Ve bu:

 // polyfills for modern browsers (if any) require('intersection-observer');

Bu, akışımızda bir dereceye kadar manuel bakım gerektiren tek adımdır. Projeye eslint-plugin-compat ekleyerek bu işlemi daha az hataya açık hale getirebiliriz. Bu eklenti, henüz çoklu doldurulmamış bir tarayıcı özelliği kullandığımızda bizi uyarır.

4. CSS Ön Eki

Son olarak, gerektirmeyen tarayıcılar için CSS öneklerini nasıl azaltabileceğimizi görelim. autoprefixer , ekosistemdeki browserslist listesi yapılandırma dosyasından okumayı destekleyen ilk araçlardan biri olduğundan, burada yapacak fazla bir şeyimiz yok.

Projenin kökünde basit bir PostCSS yapılandırma dosyası oluşturmak yeterli olacaktır:

 module.exports = { plugins: [ require('autoprefixer') ], }

Hepsini bir araya koy

Artık gerekli tüm eklenti konfigürasyonlarını tanımladığımıza göre, bunları okuyan ve dist/modern ve dist/legacy klasörlerinde iki ayrı yapı çıkaran bir web paketi konfigürasyonunu bir araya getirebiliriz.

 const MiniCssExtractPlugin = require('mini-css-extract-plugin') const isModern = process.env.BROWSERSLIST_ENV === 'modern' const buildRoot = path.resolve(__dirname, "dist") module.exports = { entry: [ isModern ? './polyfills.modern.js' : './polyfills.legacy.js', "./main.js" ], output: { path: path.join(buildRoot, isModern ? 'modern' : 'legacy'), filename: 'bundle.[hash].js', }, module: { rules: [ { test: /\.jsx?$/, use: "babel-loader" }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] } ]}, plugins: { new MiniCssExtractPlugin(), new HtmlWebpackPlugin({ template: 'index.hbs', filename: 'index.html', }), }, };

Bitirmek için package.json dosyamızda birkaç derleme komutu oluşturacağız:

 "scripts": { "build": "yarn build:legacy && yarn build:modern", "build:legacy": "BROWSERSLIST_ENV=legacy webpack -p --config webpack.config.js", "build:modern": "BROWSERSLIST_ENV=modern webpack -p --config webpack.config.js" }

Bu kadar. Çalışan yarn build vermelidir.

Kullanıcılara Doğru Paketi Sunmak

Ayrı yapılar oluşturmak, hedefimizin yalnızca ilk yarısına ulaşmamıza yardımcı olur. Hala doğru paketi tanımlamamız ve kullanıcılara sunmamız gerekiyor.

Daha önce tanımladığımız Tarayıcı listesi yapılandırmasını hatırlıyor musunuz? Kullanıcının hangi kategoriye girdiğini belirlemek için aynı konfigürasyonu kullanabilsek güzel olmaz mıydı?

Tarayıcı listesi-useragent'ı girin. Adından da anlaşılacağı gibi, browserslist-useragent , browserslist listesi yapılandırmamızı okuyabilir ve ardından bir kullanıcı aracısını ilgili ortamla eşleştirebilir. Aşağıdaki örnek bunu bir Koa sunucusuyla göstermektedir:

 const Koa = require('koa') const app = new Koa() const send = require('koa-send') const { matchesUA } = require('browserslist-useragent') var router = new Router() app.use(router.routes()) router.get('/', async (ctx, next) => { const useragent = ctx.get('User-Agent') const isModernUser = matchesUA(useragent, { env: 'modern', allowHigherVersions: true, }) const index = isModernUser ? 'dist/modern/index.html', 'dist/legacy/index.html' await send(ctx, index); });

Burada allowHigherVersions bayrağının ayarlanması, bir tarayıcının daha yeni sürümleri yayınlandığında (henüz Can I Use'ın veritabanının bir parçası olmayanlar) bunların modern tarayıcılar için doğru olarak rapor edilmesini sağlar.

browserslist-useragent işlevlerinden biri, kullanıcı aracıları eşleştirilirken platform tuhaflıklarının dikkate alınmasını sağlamaktır. Örneğin, iOS'taki (Chrome dahil) tüm tarayıcılar, temel motor olarak WebKit'i kullanır ve ilgili Safari'ye özgü Tarayıcı listesi sorgusuyla eşleştirilir.

Yalnızca üretimde kullanıcı aracısı ayrıştırmasının doğruluğuna güvenmek ihtiyatlı olmayabilir. Modern listede tanımlanmayan veya bilinmeyen veya ayrıştırılamayan kullanıcı aracısı dizelerine sahip tarayıcılar için eski pakete geri dönerek web sitemizin çalışmaya devam etmesini sağlıyoruz.

Sonuç: Buna Değer mi?

Müşterilerimize şişkinlik içermeyen paketler göndermek için uçtan uca bir akış sağlamayı başardık. Ancak bunun bir projeye eklediği bakım ek yükünün faydalarına değip değmediğini merak etmek mantıklıdır. Bu yaklaşımın artılarını ve eksilerini değerlendirelim:

1. Bakım ve Test

Bu işlem hattındaki tüm araçlara güç sağlayan yalnızca tek bir Tarayıcı listesi yapılandırmasını sürdürmek için bir tane gerekir. Modern ve eski tarayıcıların tanımlarının güncellenmesi, destekleyici yapılandırmaları veya kodu yeniden düzenlemeye gerek kalmadan gelecekte herhangi bir zamanda yapılabilir. Bunun, bakım masraflarını neredeyse ihmal edilebilir hale getirdiğini iddia ediyorum.

Bununla birlikte, her biri kendi ortamında iyi çalışması gereken iki farklı kod paketi üretmek için Babel'e güvenmekle ilişkili küçük bir teorik risk vardır.

Paketlerdeki farklılıklardan kaynaklanan hatalar nadir olsa da, bu varyantların hatalara karşı izlenmesi, sorunların belirlenmesine ve etkin bir şekilde azaltılmasına yardımcı olmalıdır.

2. Derleme Zamanı ve Çalışma Zamanı

Günümüzde yaygın olan diğer tekniklerin aksine, tüm bu optimizasyonlar oluşturma zamanında gerçekleşir ve istemci tarafından görülmez.

3. Kademeli Olarak Geliştirilmiş Hız

Modern tarayıcılardaki kullanıcıların deneyimi önemli ölçüde daha hızlı hale gelirken, eski tarayıcılardaki kullanıcılara herhangi bir olumsuz sonuç olmadan eskisi gibi aynı paket sunulmaya devam ediyor.

4. Modern Tarayıcı Özelliklerini Kolaylıkla Kullanma

Bunları kullanmak için gereken çoklu dolguların boyutu nedeniyle genellikle yeni tarayıcı özelliklerini kullanmaktan kaçınırız. Hatta bazen boyuttan tasarruf etmek için spesifikasyonlarla uyumlu olmayan daha küçük çoklu dolgular bile seçiyoruz. Bu yeni yaklaşım, tüm kullanıcıları etkileme konusunda fazla endişe duymadan spesifikasyonlarla uyumlu çoklu dolguları kullanmamıza olanak tanır.

Üretimde Diferansiyel Paket Sunumu

Önemli avantajlar göz önüne alındığında, Hindistan'ın en büyük mobilya ve dekor perakendecilerinden biri olan Urban Ladder müşterileri için yeni bir mobil ödeme deneyimi oluştururken bu yapı hattını benimsedik.

Halihazırda optimize edilmiş paketimizde, modern mobil kullanıcılara kabloyla gönderilen Gzip'd CSS ve JavaScript kaynaklarında yaklaşık %20'lik tasarruf elde etmeyi başardık. Günlük ziyaretçilerimizin %80'inden fazlası bu her zaman yeşil kalan tarayıcılarda olduğundan, harcanan çaba, etkiye değdi.

Diğer Kaynaklar

  • “Yalnızca Gerektiğinde Çoklu Dolguların Yüklenmesi”, Philip Walton
  • @babel/preset-env
    Akıllı bir Babel ön ayarı
  • Tarayıcı listesi "Araçlar"
    Browserslist için oluşturulmuş eklenti ekosistemi
  • Kullanabilirmiyim
    Mevcut tarayıcı pazar payı tablosu