Ayrıntılı ögelemeyle, Next.js ve Gatsby sayfa yükleme performansı iyileştirildi

Next.js ve Gatsby'deki daha yeni bir web paketi parçalama stratejisi, sayfa yükleme performansını iyileştirmek için yinelenen kodları en aza indirir.

Chrome, Chrome'un sunduğu araçlarla birlikte ve çerçevelerini nasıl belirleyeceğinizi öğrendiniz. Yakın zamanda bir dizi yeni optimizasyon Next.js ve yükleme performansını iyileştirmek için Gatsby Bu makalede, iyileştirilmiş bir ayrıntılı parçalama stratejisi açıklanmaktadır. Bu çerçeve artık her iki çerçevede de varsayılan olarak sunulmaktadır.

Giriş

Birçok web çerçevesi gibi Next.js ve Gatsby da temel olarak webpack'i kullanır. paketleyicidir. webpack v3 kullanıma sunuldu CommonsChunkPlugin ile şunları yapabilirsiniz: tek bir (veya birkaç) "ortak" değerde farklı giriş noktaları arasında paylaşılan çıkış modülleri parça (veya parçalar). Paylaşılan kod ayrı olarak indirilebilir ve tarayıcı önbelleğinde erkenden saklanabilir. Böylece, daha iyi yükleme performansı sağlar.

Bu kalıp, bir giriş noktası benimseyen ve birçok tek sayfalık uygulama çerçevesinin kullanıldığı paket yapılandırmasını şu şekilde görebilirsiniz:

Ortak giriş noktası ve paket yapılandırması

Paylaşılan tüm modül kodlarını tek bir parçada toplamak pratik olsa da, sınırlamaları vardır. Her giriş noktasında paylaşılmayan modüller, bunları kullanmayan rotalar için indirilebilir Bu da gerekenden daha fazla kod indirilmesine neden oluyor. Örneğin, page1 yüklendiğinde common parçasını kullanmadığınızda, page1 moduleC kullanmasa bile moduleC kodunu yükler. Bu nedenle, webpack v4, birkaç diğer eklentiyle birlikte eklentiyi yeni bir eklentiyle kaldırıyor. bir: SplitChunksPlugin.

İyileştirilmiş Chunking

SplitChunksPlugin için varsayılan ayarlar çoğu kullanıcı için uygundur. Birden çok bölünmüş parça bir dizi koşula bağlı olarak oluşturulur birden fazla rotada yinelenen kod alınmasını önlemek için.

Ancak bu eklentiyi kullanan birçok web çerçevesi hâlâ "tek ortak" bir yaklaşım izler. parçaya yaklaşım bölme. Örneğin Next.js,commons sayfaların% 50'sinden fazlasında ve tüm çerçeve bağımlılıklarında (react, react-dom vb.) kullanılıyor.

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ğlı kodu paylaşılan bir parçaya dahil etmek, ilgili kodun indirilebilir ve herhangi bir giriş noktası için önbelleğe alınmış, sayfaların yarısı çok etkili değildir. Bu oranın değiştirilmesi, yalnızca şu iki sonuçtan biriyle sonuçlanır:

  • Bu oranı düşürürseniz daha fazla gereksiz kod indirilir.
  • Bu oranı artırırsanız birden fazla rotada daha fazla kod yinelenir.

Bu sorunu çözmek için Next.js, farklı bir yaklaşım SplitChunksPlugin için yapılandırmanın gereksiz koda ihtiyacınız yok.

  • Yeterli büyüklükte olan üçüncü taraf modülleri (160 KB'tan büyük), kendi bağımsız modüllerine bölünür parça
  • Çerçeve bağımlılıkları (react, react-dom veframeworks vb.)
  • Gerektiği kadar paylaşılan parça oluşturulur (en fazla 25)
  • Yığının oluşturulması için minimum boyut 20 KB olarak değiştirildi

Bu ayrıntılı parçalama stratejisi şu avantajları sağlar:

  • Sayfa yüklenme süreleri iyileştirildi. Tek bir parça yerine birden çok paylaşılan parça göndermek, herhangi bir giriş noktası için gereksiz (veya yinelenen) kod miktarını en aza indirir.
  • Gezinme sırasında daha iyi önbellek kullanımı. Büyük kitaplıkları ve çerçeve bağımlılıklarını bölme çok küçük parçalara ayırması önbelleğin geçersiz kılınma olasılığını azaltır. Çünkü bunların her ikisi de değişiklik yapılana kadar değişiklik gösterebilir.

Next.js'nin benimsediği yapılandırmanın tamamını webpack-config.ts'te görebilirsiniz.

Diğer HTTP istekleri

SplitChunksPlugin, ayrıntılı parçalamanın temelini tanımlamış ve bu yaklaşımı çerçevesi tamamen yeni bir kavram değildi. Ancak birçok çerçeve yine de tek bir bulgusal ve "ortak" kullanın birkaç nedene dayanır. Bu, proje yöneticisinin HTTP isteği sayısının artması site performansını olumsuz yönde etkileyebilir.

Tarayıcılar tek bir kaynağa (Chrome için 6) yalnızca sınırlı sayıda TCP bağlantısı açabilir. bir paketleyici tarafından üretilen parçaların sayısını en aza indirmek, toplam istek sayısının bu eşiğin altında kalır. Ancak bu yalnızca HTTP/1.1 için geçerlidir. HTTP/2'de Multiplexleme Tek bir bağlantı üzerinden tek bir bağlantı kullanarak birden fazla isteğin paralel olarak akışına olanak tanır. kaynak. Diğer bir deyişle, genellikle parça sayısını sınırlama konusunda endişelenmemize gerek kalmaz yayınlanmıştır.

Başlıca tarayıcıların tümü HTTP/2'yi desteklemektedir. Chrome ve Next.js ekipleri Next.js'nin tek "ortak" öğelerini bölerek istek sayısını artırıp artırmadığını görmek istedim grup ayırabilmeniz, yükleme performansını herhangi bir şekilde etkileyecektir. İlk olarak aynı site bağlantısını kullanarak maksimum paralel istek sayısını değiştirirken maxInitialRequests

İstek sayısındaki artışla birlikte sayfa yükleme performansı

Tek bir web sayfasında yapılan birden fazla denemenin ortalama olarak üç kez çalıştırılmasında, load, start-render ve First Contentful Paint süreleri, maksimum başlangıç değeri değiştirilirken yaklaşık olarak aynı kaldı. istek sayısı (5 ila 15). İşin ilginç yanı, bu modelde yalnızca biraz performansın bölünmesinin ardından %65'lik bir artışa yol açabilir.

Yüzlerce istekle sayfa yükleme performansı

Bu veriler, güvenilir bir eşiğin (20~25 istek) altında kalmanın doğru dengeyi yakaladığını gösterdi. performansı ve önbellek verimliliği arasında bir denge kurmak için idealdir. Bazı temel testlerden sonra 25 katılımcı maxInitialRequest sayısı.

Paralel olarak gerçekleşen maksimum istek sayısının değiştirilmesi, birden fazla istekle sonuçlandı ve bunları her giriş noktası için uygun şekilde ayırmak, paylaşılan pakete gerekli olmayan kod miktarını belirleyin.

Daha fazla parçalama ile JavaScript yükünü azaltır

Bu deneme yalnızca, istek sayısında değişiklik yapılıp yapılmayacağını görmekle ilgiliydi. sayfa yükleme performansını olumsuz etkiler. Sonuçlar, maxInitialRequests politikasının Test sayfasındaki 25, JavaScript yük boyutunu yavaşlatmadan küçülttüğü için optimumdu bir şeyler üretebilirsiniz. Sayfayı sadeleştirmek için gereken toplam JavaScript miktarı hâlâ mevcut hemen hemen aynıdır; bu da sayfa yükleme performansının, yüklemelerdeki düşüşle birlikte gerekir.

webpack, bir parçanın oluşturulması için varsayılan minimum boyut olarak 30 KB kullanır. Ancak, bir Minimum 20 KB boyuta sahip 25 maxInitialRequests değeri, bunun yerine daha iyi önbelleğe almayla sonuçlandı.

Ayrıntılı parçalarla boyut küçültme

Next.js dahil olmak üzere birçok çerçeve, komut dosyası etiketleri oluşturmanız gerekir. Peki bu dinamik parçaları derleme sırasında nasıl önceden belirleyebilirler?

Next.js, hangi çıktı parçalarının kullanıldığını belirlemek için sunucu tarafı bir derleme manifesti dosyası kullanır: giriş noktalarından yararlanabilirsiniz. Bu bilgiyi müşteriye de sağlamak için kısaltılmış istemci tarafı her giriş noktasında tüm bağımlıların eşlenmesi için derleme manifest 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}`)) || []
  )
}
Bir Next.js uygulamasında birden fazla paylaşılan parçanın çıkışı.

Bu yeni ayrıntılı parçalama stratejisi, ilk olarak Next.js'de bir işaretin arkasında kullanıma sunuldu. Bu strateji, ilk olarak ilk kullanıcılardan oluşur. Pek çok kişi, Arkadaş Bitkiler projesinde kullanılan toplam JavaScript tüm site:

'nı inceleyin.
Web sitesi Toplam JS Değişikliği % Farkı
https://www.barnebys.com/ -238 KB -%23
https://sumup.com/ -220 KB -%30
https://www.hashicorp.com/ -11 MB -%71
JavaScript boyutu düşüşleri (tüm rotalarda (sıkıştırılmış))

Nihai sürüm 9.2 sürümünde varsayılan olarak kullanıma sunulmuştur.

Gatsby

Gatsby eskiden, kullanıma dayalı bir dönüşüm yönetimi yaklaşımı genel modülleri tanımlamak için sezgisel:

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)[\\/]/,
      },

Ayrıca, web paketi yapılandırmasını benzer bir ayrıntılı parçalama stratejisi benimseyecek şekilde optimize ederek JavaScript'in pek çok büyük sitede büyük oranda azaldığını fark ettik:

'nı inceleyin.
Web sitesi Toplam JS Değişikliği % Farkı
https://www.gatsbyjs.org/ -680 KB -%22
https://www.thirdandgrove.com/ -390 KB -%25
https://ghost.org/ -1,1 MB -%35
https://reactjs.org/ -80 KB -%8
JavaScript boyutu düşüşleri (tüm rotalarda (sıkıştırılmış))

Bu politikaların nasıl uygulandığını anlamak için PR'ye 2.20.7 sürümünde varsayılan olarak gönderilen web paketi yapılandırmasına bu mantığı uyguladı.

Sonuç

Ayrıntılı parçaları gönderme kavramı Next.js, Gatsby'ye, hatta webpack'e özgü değildir. Herkes geniş bir "ortak paydada" buluşması durumunda, uygulamanın parçalama stratejisini iyileştirmeyi düşünmelidirler. paket yaklaşımını kullanmanız gerekir.

  • Aynı parçalama optimizasyonlarının vanilla React uygulamasına uygulanmasını görmek isterseniz bu örnek React'e göz atın uygulamasında gösterilir. Bir ayrıntılı parçalama stratejisinin basitleştirilmiş sürümüdür ve aynısını uygulamaya başlamanıza bir anlam ifade eder.
  • Birleştirme için parçalar varsayılan olarak ayrıntılı bir şekilde oluşturulur. Şu bilgileri inceleyin: Manuel olarak etkinleştirmek için manualChunks ve davranışı yapılandırın.