Web paketinde bir betiği değerlendirmeden nasıl alabilirim?


9

Son zamanlarda bazı web sitesi optimizasyon çalışmaları üzerinde çalışıyorum ve bu gibi alma deyimi kullanarak web paketinde kod bölme kullanmaya başlıyorum:

import(/* webpackChunkName: 'pageB-chunk' */ './pageB')

Hangi doğru pageB-chunk.js oluşturmak , şimdi diyelim ki sayfa A bu yığın yığın önceden istiyorum , sayfa A bu ifadeyi ekleyerek bunu yapabilirsiniz:

import(/* webpackChunkName: 'pageB-chunk' */ /* webpackPrefetch: true */ './pageB')

Bu da bir

<link rel="prefetch" href="pageB-chunk.js">

HTML'nin başına eklenirse, tarayıcı şimdiye kadar çok iyi bir şekilde önceden getirecektir.

Sorun burada kullandığım ithalat deyimi sadece js dosyasını önceden getirmekle kalmaz, aynı zamanda js dosyasını da değerlendirir, js dosyasının kodunun ayrıştırıldığı ve bayt kodlarına derlendiği anlamına gelir, bu JS'nin üst düzey kodu yürütülür.

Bu bir mobil cihazda çok zaman alan bir işlemdir ve optimize etmek istiyorum, sadece ön getirme bölümünü istiyorum, değerlendirme ve yürütme parçasını istemiyorum , çünkü daha sonra bazı kullanıcı etkileşimleri gerçekleştiğinde, ayrışmayı tetikleyeceğim & kendimi değerlendir

resim açıklamasını buraya girin

Only Sadece ilk iki adımı tetiklemek istiyorum, resimler https://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/ adresinden geliyor ↑↑↑↑↑↑↑ ↑↑

Tabii ki önceden getirme bağlantısını kendim ekleyerek yapabilirim, ancak bu, önceden getirme bağlantısına hangi URL'yi koymam gerektiğini bilmem gerektiği anlamına gelir, webpack bu URL'yi kesinlikle biliyor, web paketinden nasıl alabilirim?

Webpack'in bunu başarmanın kolay bir yolu var mı?


if (false) import(…)- Webpack'in ölü kod analizi yaptığından şüpheliyim?
Bergi

Nerede / ne zaman do aslında modülünü değerlendirmek istiyoruz? Dinamik importkodun gitmesi gereken yer burasıdır .
Bergi

Şimdi çok kafam karıştı. Değerlendirme neden önemlidir? çünkü sonunda JS dosyası, istemci tarayıcı cihazı tarafından değerlendirilmelidir. Ya da soruyu doğru anlamıyorum.
AmerllicA

@AmerllicA sonunda js değerlendirilmelidir, ancak bu durumu düşünün: Web sitemde A, B iki sayfa var, sayfa A'daki ziyaretçiler, sayfa A'da "bazı işler yaptıktan" sonra sayfa B'yi sık sık ziyaret ediyor. JS, ancak bu B'nin JS değerlendirildiği zamanı kontrol edebilirsem, ziyaretçi A sayfalarını "işlerini yapmaya" çalışırken hata oluşturan ana iş parçacığını engellemediğimden% 100 emin olabilirim. Ziyaretçi B sayfasına yönlendiren bir bağlantıyı tıkladıktan sonra B'nin JS'si, ancak o zaman B'nin JS'si büyük olasılıkla indiriliyor, değerlendirmek için biraz zaman harcaman gerekiyor.
migcoder

Tabii krom V8 'günlüğü göre: v8.dev/blog/cost-of-javascript-2019 , burada da, ayrıntıları İşçi iplik ve diğer birçok teknisyenler kullanarak, zaman ayrıştırma çarpıcı hızda JS ulaşmak için bir çok iyileştirmeler yaptım youtube.com / watch? v = D1UJgiG4_NI . Ancak diğer tarayıcılar henüz bu tür bir optimizasyon uygulamamaktadır.
migcoder

Yanıtlar:


1

GÜNCELLEME

Html -webpack-eklentisi ile preload-webpack-eklentisini kullanabilirsiniz , yapılandırmada neyin önceden yükleneceğini tanımlamanıza izin verir ve yığınınızı önceden yüklemek için otomatik olarak etiketler ekler

şu anda webpack v4 kullanıyorsanız, bu eklentiyi kullanarak preload-webpack-plugin@next

misal

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    include: 'asyncChunks'
  })
]

Dinamik olarak oluşturulmuş adlara sahip iki eşzamansız komut dosyası üreten bir proje için, chunk.31132ae6680e598f8879.jsve chunk.d15e7fdfc91b34bb78c4.jsgibi, aşağıdaki önyüklemeler belgeye enjekte edilirhead

<link rel="preload" as="script" href="chunk.31132ae6680e598f8879.js">
<link rel="preload" as="script" href="chunk.d15e7fdfc91b34bb78c4.js">

GÜNCELLEME 2

tüm zaman uyumsuz yığınları önceden yüklemek istemezseniz, ancak bunu yapabildiğinizde yalnızca bir kez

Ya kullanabilirsiniz eklentisi en migcoder Babel veya preload-webpack-pluginaşağıdaki gibi

  1. ilk olarak, bu async yığınını webpack magic commentörnek yardımıyla adlandırmanız gerekecek

    import(/* webpackChunkName: 'myAsyncPreloadChunk' */ './path/to/file')
  2. ve eklenti yapılandırmasında şu adı kullanın:

    plugins: [
      new HtmlWebpackPlugin(),   
      new PreloadWebpackPlugin({
        rel: 'preload',
        include: ['myAsyncPreloadChunk']
      }) 
    ]
    

Öncelikle komut dosyasını yüklemek için scriptetiket veya linketiket belirlediğimizde tarayıcının davranışını görelim

  1. bir tarayıcı bir scriptetiketle karşılaştığında etiketi yükler ve hemen yürütür
  2. ayrıştırma ve değerlendirmeyi yalnızca etkinlik asyncve deferetiket yardımı ile yalnızcaDOMContentLoaded etkinliğe kadar geciktirebilirsiniz
  3. komut dosyası etiketini eklemezseniz yürütmeyi (değerlendirmeyi) geciktirebilirsiniz (yalnızca ile önceden yükleyin link)

Şimdi diğer bazı vardır önerilmez hackey yolu tüm komut ve gemi olan stringveya comment(yorum veya dize değerlendirme süresi yok denecek kadar azdır çünkü) ile kendinizin kullanabileceği yürütmek gerektiğinde Function() constructorveya evalher ikisi tavsiye edilmez


Başka Bir Yaklaşım Hizmeti Çalışanları: (sayfa yeniden yüklendikten sonra önbellek olayını koruyacak veya önbellek yüklendikten sonra kullanıcı çevrimdışı duruma gelecektir)

Modern tarayıcıda, service workerbir başvuruyu (JavaScript, resim, css şey) almak ve önbelleğe almak için kullanabilirsiniz ve bu başvuru için ana iş parçacığı talebi söz konusu olduğunda, bu isteği kesebilir ve başvuruyu önbellekten bu şekilde geri gönderemezsiniz. önbelleğe yüklüyorsunuz burada servis çalışanları hakkında daha fazla bilgi edinin

misal

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(caches.match(event.request).then(function(response) {
    // caches.match() always resolves
    // but in case of success response will have value
    if (response !== undefined) {
      return response;
    } else {
      return fetch(event.request).then(function (response) {
        // response may be used only once
        // we need to save clone to put one copy in cache
        // and serve second one
        let responseClone = response.clone();

        caches.open('v1').then(function (cache) {
          cache.put(event.request, responseClone);
        });
        return response;
      }).catch(function () {
        // any fallback code here
      });
    }
  }));
});

Gördüğünüz gibi bu webpack bağımlı bir şey değil, bu webpack kapsamı dışındadır, ancak webpack yardımıyla servis çalışanını daha iyi kullanmanıza yardımcı olacak paketinizi bölebilirsiniz


ama yine de benim acı nokta, web paketinden kolayca dosyanın URL'sini alamıyorum, ben SW ile gitmek, ben hala SW hangi dosyaların önbellek olması gerektiğini bildirmek gerekiyor ... webpack manifest eklentisi içine manifest bilgi üretebilir SW, ama bu bir operasyonda, SW manifest listelenen tüm dosyaları önbellek ön seçeneği yok anlamına gelir ...
migcoder

İdeal olarak, webpack'in / * webpackOnlyPrefetch: true * / gibi başka bir sihirli yorum ekleyebileceğini umuyorum, bu yüzden her tembel yüklenebilir yığın için iki kez içe aktarma ifadesini çağırabilirim;
migcoder

1
@migcoder bu geçerli bir nokta (çünkü çalışma zamanında dinamik olarak oluşturulan dosya adını alamıyorsunuz) herhangi bir çözüm bulabilirsem herhangi bir çözüm
arayacaktır

@migcoder Cevabını güncelledim, lütfen sorununuzu çözdüğünü görün
Tripurari Shankar

sorunun bir kısmını çözerse, bu async parçalarını filtreleyebilir, ancak son hedefim sadece async parçalarını önceden getirmektir. Şu anda bu eklentiye bakıyorum github.com/sebastian-software/babel-plugin-smart-webpack-import , bana nasıl tüm ithalat ifadeleri toplamak ve sihirli yorum bazı kod değişiklik tabanı yapmak gösterir, belki ben oluşturabilir 'webpackOnlyPrefetch: true' sihirli yorumu ile içe aktarma ifadelerine ön alma kodunu eklemek için benzer bir eklenti.
migcoder

1

Güncellemeler: Her şeyi bir npm paketine dahil ediyorum, kontrol edin! https://www.npmjs.com/package/webpack-prefetcher


Birkaç günlük araştırmadan sonra, özel bir babel eklentisi yazıyorum ...

Kısacası, eklenti şu şekilde çalışır:

  • Koddaki tüm import (args) ifadelerini toplayın
  • Eğer ithalat (args) içeren / * getirilmeyen: true * / yorum
  • Bul chunkId dan ithal () deyimi
  • Prefetcher.fetch (chunkId) ile değiştirin

Prefetcher, webpack çıktısının manifest'ini içeren bir yardımcı sınıftır ve prefetch bağlantısını eklememize yardımcı olabilir:

export class Prefetcher {
  static manifest = {
    "pageA.js": "/pageA.hash.js",
    "app.js": "/app.hash.js",
    "index.html": "/index.html"
  }
  static function fetch(chunkId) {
    const link = document.createElement('link')
    link.rel = "prefetch"
    link.as = "script"
    link.href = Prefetcher.manifest[chunkId + '.js']
    document.head.appendChild(link)
  }
}

Bir kullanım örneği:

const pageAImporter = {
  prefetch: () => import(/* prefetch: true */ './pageA.js')
  load: () => import(/* webpackChunkName: 'pageA' */ './pageA.js')
}

a.onmousehover = () => pageAImporter.prefetch()

a.onclick = () => pageAImporter.load().then(...)

Bu eklentinin detayını burada bulabilirsiniz:

Prefetch - Web paketinden kontrolü elinize alın

Yine, bu gerçekten hacky bir yoldur ve webpack ekibinin bunu uygulamasını istiyorsanız, lütfen buraya oy verin:

Özelliği: istek üzerine dinamik ithalat prefetch


0

Neyi başarmaya çalıştığınızı anladığımı varsayarak, belirli bir olaydan sonra bir modülü ayrıştırmak ve yürütmek istiyorsunuz (örn. Bir düğmeyi tıklayın). İçe aktarma ifadesini bu etkinliğin içine yerleştirebilirsiniz:

element.addEventListener('click', async () => {
  const module = await import("...");
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.