Chrome, JavaScript açık kaynak ekosistemindeki araçlar ve çerçevelerle işbirliği yapıyor. Yükleme performansını iyileştirmek için yakın zamanda bir dizi yeni optimizasyon eklendi. Sonraki.js Ve Gatsby. Bu makale, artık her iki çerçevede de varsayılan olarak gönderilen gelişmiş bir parçalı parçalama stratejisini ele almaktadır.
giriiş #
Birçok web çerçevesi gibi, Next.js ve Gatsby de web paketi çekirdek paketleyicileri olarak. webpack v3 tanıtıldı CommonsChunkPlugin
tek bir (veya birkaç) “ortak” yığında (veya yığınlarda) farklı giriş noktaları arasında paylaşılan modüllerin çıktısını almayı mümkün kılmak için. Paylaşılan kod ayrı olarak indirilebilir ve daha erken bir zamanda tarayıcı önbelleğinde saklanabilir, bu da daha iyi bir yükleme performansıyla sonuçlanabilir.
Bu model, şuna benzeyen bir giriş noktası ve paket yapılandırmasını benimseyen birçok tek sayfalık uygulama çerçevesinde popüler hale geldi:
Pratik olmasına rağmen, tüm paylaşılan modül kodunu tek bir öbek halinde birleştirme kavramının sınırlamaları vardır. Her giriş noktasında paylaşılmayan modüller, onu kullanmayan rotalar için indirilebilir ve bu da gereğinden fazla kodun indirilmesine neden olur. Örneğin, ne zaman page1
yükler common
yığın, için kodu yükler moduleC
rağmen page1
kullanmaz moduleC
. Bu nedenle, diğer birkaç eklentiyle birlikte webpack v4, eklentiyi yeni bir eklenti lehine kaldırdı: SplitChunksPlugin
.
Geliştirilmiş Parçalama #
için varsayılan ayarlar SplitChunksPlugin
çoğu kullanıcı için iyi çalışır. Sayısına bağlı olarak birden çok bölünmüş parça oluşturulur. koşullar birden çok rotada yinelenen kodun alınmasını önlemek için.
Bununla birlikte, bu eklentiyi kullanan birçok web çerçevesi, yığın bölme için hala bir “tek ortak nokta” yaklaşımını izlemektedir. Örneğin, Next.js bir commons
sayfaların %50’sinden fazlasında kullanılan herhangi bir modülü ve tüm çerçeve bağımlılıklarını içeren paket (react
, react-dom
ve benzeri).
const splitChunksConfigs = {
…
prod: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
commons: {
name: 'commons',
chunks: 'all',
minChunks: totalPages > 2 ? totalPages * 0.5 : 2,
},
react: {
name: 'commons',
chunks: 'all',
test: /[\\/]node_modules[\\/](react|react-dom|scheduler|use-subscription)[\\/]/,
},
},
},
Çerçeveye bağımlı kodu paylaşılan bir yığına dahil etmek, herhangi bir giriş noktası için indirilebileceği ve önbelleğe alınabileceği anlamına gelse de, kullanıma dayalı ortak modülleri dahil etme buluşsal yöntemi birden fazla yerde kullanılır. sayfaların yarısı çok etkili değil Bu oranı değiştirmek yalnızca iki sonuçtan biriyle sonuçlanır:
- Oranı düşürürseniz, daha fazla gereksiz kod indirilir.
- Oranı artırırsanız, birden çok yol boyunca daha fazla kod çoğaltılır.
Bu sorunu çözmek için Next.js bir farklı konfigürasyon içinSplitChunksPlugin
bu, herhangi bir rota için gereksiz kodu azaltır.
- Yeterince büyük olan herhangi bir üçüncü taraf modülü (160 KB’den büyük) kendi ayrı öbeğine bölünür
- ayrı bir
frameworks
yığın, çerçeve bağımlılıkları için oluşturulur (react
,react-dom
ve benzeri) - Gerektiği kadar paylaşılan parça oluşturulur (en fazla 25)
- Oluşturulacak bir yığın için minimum boyut 20 KB olarak değiştirildi
Bu ayrıntılı parçalama stratejisi aşağıdaki faydaları sağlar:
- Sayfa yükleme süreleri iyileştirildi. Tek bir parça yerine birden fazla paylaşılan parça yayınlamak, herhangi bir giriş noktası için gereksiz (veya yinelenen) kod miktarını en aza indirir.
- Navigasyonlar sırasında iyileştirilmiş önbelleğe alma. Büyük kitaplıkları ve çerçeve bağımlılıklarını ayrı parçalara bölmek, bir yükseltme yapılana kadar her ikisinin de değişme olasılığı düşük olduğundan, önbellek geçersiz kılma olasılığını azaltır.
Next.js’nin benimsediği yapılandırmanın tamamını görebilirsiniz. webpack-config.ts
.
Daha fazla HTTP isteği #
SplitChunksPlugin
ayrıntılı parçalamanın temelini tanımladı ve bu yaklaşımı Next.js gibi bir çerçeveye uygulamak tamamen yeni bir kavram değildi. Bununla birlikte, birçok çerçeve, birkaç nedenden ötürü tek bir sezgisel ve “ortak” paket stratejisini kullanmaya devam etti. Buna, daha birçok HTTP isteğinin site performansını olumsuz yönde etkileyebileceği endişesi de dahildir.
Tarayıcılar, tek bir kaynağa (Chrome için 6) yalnızca sınırlı sayıda TCP bağlantısı açabilir, bu nedenle bir paket oluşturucu tarafından çıkarılan parça sayısını en aza indirmek, toplam istek sayısının bu eşiğin altında kalmasını sağlayabilir. Ancak bu yalnızca HTTP/1.1 için geçerlidir. HTTP/2’de çoklama, birden çok isteğin tek bir kaynak üzerinden tek bir bağlantı kullanılarak paralel olarak yayınlanmasına olanak tanır. Başka bir deyişle, genellikle paketleyicimiz tarafından yayılan parça sayısını sınırlama konusunda endişelenmemize gerek yoktur.
Tüm büyük tarayıcılar HTTP/2’yi destekler. Chrome ve Next.js ekipleri, Next.js’nin tek “ortak” paketini birden fazla paylaşılan parçaya bölerek istek sayısını artırmanın yükleme performansını herhangi bir şekilde etkileyip etkilemeyeceğini görmek istedi. kullanarak maksimum paralel istek sayısını değiştirirken tek bir sitenin performansını ölçerek başladılar. maxInitialRequests
mülk.
Tek bir web sayfasında birden fazla denemenin ortalama üç çalıştırmasında, load
, start-render ve First Contentful Paint sürelerinin tümü, maksimum ilk istek sayısını değiştirirken (5’ten 15’e) hemen hemen aynı kaldı. Yeterince ilginç bir şekilde, yalnızca agresif bir şekilde yüzlerce isteğe böldükten sonra performansta hafif bir ek yük fark ettik.
Bu, güvenilir bir eşiğin (20~25 istek) altında kalmanın, yükleme performansı ile önbelleğe alma verimliliği arasında doğru dengeyi kurduğunu gösterdi. Bazı temel testlerden sonra, 25 olarak seçildi. maxInitialRequest
saymak.
Paralel gerçekleşen maksimum istek sayısını değiştirmek, birden fazla paylaşılan paketle sonuçlandı ve bunları her giriş noktası için uygun şekilde ayırmak, aynı sayfa için gereksiz kod miktarını önemli ölçüde azalttı.
Bu deney, yalnızca sayfa yükleme performansı üzerinde herhangi bir olumsuz etki olup olmayacağını görmek için istek sayısını değiştirmekle ilgiliydi. Sonuçlar, ayarın maxInitialRequests
ile 25
JavaScript veri yükünün boyutunu sayfayı yavaşlatmadan azalttığı için test sayfasında en uygun düzeydeydi. Sayfayı nemlendirmek için gereken toplam JavaScript miktarı yaklaşık olarak aynı kaldı, bu da sayfa yükleme performansının neden azaltılan kod miktarıyla iyileşmediğini açıklıyor.
webpack, oluşturulacak bir öbek için varsayılan minimum boyut olarak 30 KB kullanır. Ancak, birleştirme maxInitialRequests
bunun yerine 20 KB minimum boyutla 25 değeri daha iyi önbelleğe almayla sonuçlandı.
Granüler parçalarla boyut küçültme #
Next.js de dahil olmak üzere birçok çerçeve, her yol geçişi için daha yeni komut dosyası etiketleri eklemek için istemci tarafı yönlendirmeye (JavaScript tarafından işlenir) güvenir. Ancak bu dinamik parçaları oluşturma zamanında nasıl önceden belirliyorlar?
Next.js, hangi çıkış parçalarının farklı giriş noktaları tarafından kullanıldığını belirlemek için bir sunucu tarafı derleme manifest dosyası kullanır. Bu bilgileri istemciye de sağlamak için, her giriş noktası için tüm bağımlılıkları eşlemek üzere kısaltılmış bir istemci tarafı derleme bildirim dosyası oluşturuldu.
// Returns a promise for the dependencies for a particular route
getDependencies (route) {
return this.promisedBuildManifest.then(
man => (man[route] && man[route].map(url => `/_next/${url}`)) || []
)
}
Bu daha yeni ayrıntılı parçalama stratejisi ilk olarak Next.js’de bir bayrağın arkasında kullanıma sunuldu ve burada birkaç erken benimseyenler üzerinde test edildi. Birçoğu, sitelerinin tamamı için kullanılan toplam JavaScript’te önemli düşüşler gördü:
Nihai sürüm, varsayılan olarak şu tarihte gönderilmiştir: sürüm 9.2.
Gatsby #
Gatsby ortak modülleri tanımlamak için kullanıma dayalı bir buluşsal yöntem kullanmayla aynı yaklaşımı izlemek için kullanılır:
config.optimization = {
…
splitChunks: {
name: false,
chunks: `all`,
cacheGroups: {
default: false,
vendors: false,
commons: {
name: `commons`,
chunks: `all`,
// if a chunk is used more than half the components count,
// we can assume it's pretty global
minChunks: componentsCount > 2 ? componentsCount * 0.5 : 2,
},
react: {
name: `commons`,
chunks: `all`,
test: /[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/,
},
Web paketi yapılandırmalarını benzer bir parçalı parçalama stratejisini benimsemek üzere optimize ederek, birçok büyük sitede oldukça büyük JavaScript azalmaları da fark ettiler:
şuna bir bak halkla ilişkiler v2.20.7’de varsayılan olarak gönderilen web paketi yapılandırmalarına bu mantığı nasıl uyguladıklarını anlamak için.
Çözüm #
Parçalı parçaları gönderme kavramı, Next.js, Gatsby ve hatta webpack’e özgü değildir. Kullanılan çerçeve veya modül paketleyiciden bağımsız olarak, büyük bir “ortak” paket yaklaşımını izliyorsa, herkes uygulamalarının parçalama stratejisini geliştirmeyi düşünmelidir.
- Bir klasik React uygulamasına uygulanan aynı yığın optimizasyonlarını görmek isterseniz, buna bir göz atın örnek React uygulaması. Ayrıntılı parçalama stratejisinin basitleştirilmiş bir sürümünü kullanır ve aynı tür mantığı sitenize uygulamaya başlamanıza yardımcı olabilir.
- Toplama için, parçalar varsayılan olarak parçalı olarak oluşturulur. Şuna baksana
manualChunks
davranışı manuel olarak yapılandırmak isterseniz.