Akıllı Paketleme: Eski Kodu Yalnızca Eski Tarayıcılara Nasıl Sunulur
Yayınlanan: 2022-03-10Gü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?
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.
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.
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.
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