वेबपैक पर मैं मूल्यांकन किए बिना स्क्रिप्ट कैसे आयात कर सकता हूं?


9

मैं हाल ही में कुछ वेबसाइट अनुकूलन कार्यों पर काम कर रहा हूं, और मैं इस तरह के आयात विवरण का उपयोग करके वेबपैक में कोड विभाजन का उपयोग करना शुरू करता हूं:

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

कौन सा सही ढंग से बनाने pageB-chunk.js , अब मान लीजिए कि मैं करना चाहते हैं prefetch pageA में यह हिस्सा है, मैं द्वारा यह कर सकते हैं pageA में इस बयान जोड़ें:

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

जिसका परिणाम होगा

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

HTML के प्रमुख के रूप में जोड़ा जा रहा है, फिर ब्राउज़र इसे प्रीफ़ैच करेगा, अब तक बहुत अच्छा है।

समस्या यह है कि मैं यहाँ जेएस फ़ाइल को प्रीफ़ैच नहीं करता, बल्कि जेएस फ़ाइल का मूल्यांकन करता हूँ, इसका उपयोग आयात विवरण है, इसका मतलब है कि जेएस फ़ाइल का कोड पार्स किया गया है और बायटकोड को संकलित किया गया है, उस जेएस के शीर्ष-स्तरीय कोड को निष्पादित किया गया है।

यह एक मोबाइल डिवाइस पर बहुत समय लेने वाला ऑपरेशन है और मैं इसे ऑप्टिमाइज़ करना चाहता हूं, मैं केवल प्रीफैच भाग चाहता हूं, मैं भाग का मूल्यांकन और निष्पादन नहीं चाहता हूं , क्योंकि बाद में जब कुछ उपयोगकर्ता इंटरैक्शन होते हैं, तो मैं पार्सिंग को ट्रिगर करूंगा और खुद का मूल्यांकन करें

यहां छवि विवरण दर्ज करें

↑↑↑↑↑↑↑↑ मैं केवल पहले दो चरणों को ट्रिगर करना चाहता हूं, चित्र https://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/ https: // से आते हैं ↑↑

निश्चित रूप से मैं खुद प्रीफैच लिंक जोड़कर ऐसा कर सकता हूं, लेकिन इसका मतलब यह है कि मुझे यह जानने की जरूरत है कि मुझे कौन सा यूआरएल प्रीफच लिंक में डालना चाहिए, वेबपैक इस यूआरएल को जरूर जानता है, मैं इसे वेबपैक से कैसे प्राप्त कर सकता हूं?

क्या वेबपैक के पास इसे हासिल करने का कोई आसान तरीका है?


if (false) import(…)- मुझे संदेह है कि वेबपैक मृत कोड विश्लेषण करता है?
बरगी

कहाँ / जब करते हैं तो आप वास्तव में मॉड्यूल का मूल्यांकन करना चाहते हैं? वहीं डायनेमिक importकोड जाना चाहिए।
बरगी

मैं अब बहुत उलझन में हूँ। मूल्यांकन क्यों महत्वपूर्ण है? क्योंकि अंतिम बार, जेएस फ़ाइल का मूल्यांकन क्लाइंट ब्राउज़र डिवाइस द्वारा किया जाना चाहिए। या मैं इस सवाल को सही ढंग से नहीं समझता।
आम्र्लिसिका

@AmerllicA ने आखिरकार js का मूल्यांकन किया जाना चाहिए, लेकिन इस मामले को सोचें: मेरी वेबसाइट को A, B दो पृष्ठ मिले, पृष्ठ A में आगंतुक अक्सर पृष्ठ B पर जाते हैं, जब वे पृष्ठ A पर "कुछ काम करते हैं" के बाद फिर पृष्ठ B को पूर्वनिर्मित करना उचित है जेएस, लेकिन अगर मैं उस समय को नियंत्रित कर सकता हूं जिस पर इस बी के जेएस का मूल्यांकन किया जाता है, तो मैं 100% सुनिश्चित कर सकता हूं कि मैं मुख्य थ्रेड को ब्लॉक नहीं करता हूं जो जब पृष्ठ ए पर आगंतुक "अपने काम करता है" का मूल्यांकन कर रहा है, तो मैं मूल्यांकन कर सकता हूं। विज़िटर के बाद B का JS एक लिंक पर क्लिक करता है जो पेज B की ओर इशारा करता है, लेकिन उस समय B का JS सबसे अधिक संभावना है, मुझे इसका मूल्यांकन करने के लिए बस थोड़ा समय बिताने की आवश्यकता है।
माइग्रोडर

क्रोम v8 के ब्लॉग के अनुसार ज़रूर: v8.dev/blog/cost-of-javascript-2019 , उन्होंने मज़दूरों के मज़बूत जेएस पार्सिंग टाइम को हासिल करने के लिए बहुत से अनुकूलन किए, वर्कर थ्रेड और कई टेक तकनीक का उपयोग करके, यहाँ youtube.com में विवरण दिया। / घड़ी? v = D1UJgiG4_NI । लेकिन अन्य ब्राउज़र अभी तक इस तरह के अनुकूलन को लागू नहीं करते हैं।
माइग्रोडर

जवाबों:


1

अपडेट करें

आप html -webpack-plugin के साथ प्रीलोड-वेबपैक-प्लगइन का उपयोग कर सकते हैं, यह आपको परिभाषित करने देगा कि कॉन्फ़िगरेशन में क्या प्रीलोड करना है और यह आपके चंक को प्रीलोड करने के लिए स्वचालित रूप से टैग डालेगा

ध्यान दें कि यदि आप अभी वेबपैक v4 का उपयोग कर रहे हैं तो आपको इस प्लगइन का उपयोग करके इंस्टॉल करना होगा preload-webpack-plugin@next

उदाहरण

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

गतिशील रूप से उत्पन्न नामों के साथ दो async स्क्रिप्ट बनाने वाली परियोजना के लिए, जैसे कि chunk.31132ae6680e598f8879.jsऔर chunk.d15e7fdfc91b34bb78c4.js, निम्नलिखित प्रीलोड्स को दस्तावेज़ में इंजेक्ट किया जाएगा।head

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

अद्यतन २

यदि आप सभी async chunk को प्रीलोड नहीं करना चाहते हैं, लेकिन केवल एक बार ही आप इसे कर सकते हैं

या तो आप माइगोडर के बेबल प्लगइन का उपयोग कर सकते हैं या preload-webpack-pluginनिम्नलिखित की तरह

  1. सबसे पहले आपको उस async चंक को webpack magic commentउदाहरण की मदद से नाम देना होगा

    import(/* webpackChunkName: 'myAsyncPreloadChunk' */ './path/to/file')
  2. और फिर प्लगइन कॉन्फ़िगरेशन में उस नाम का उपयोग करें जैसे

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

जब हम स्क्रिप्ट लोड करने के लिए scriptटैग या linkटैग निर्दिष्ट करते हैं, तो सबसे पहले हम ब्राउज़र के व्यवहार को देखते हैं

  1. जब भी कोई ब्राउज़र एक scriptटैग का सामना करता है तो वह उसे पार्स कर देगा और तुरंत निष्पादित करेगा
  2. आप केवल तब तक पार्सिंग और मूल्यांकन में देरी कर सकते हैं जब तक कि केवल ईवेंट asyncऔर deferटैग की मदद से मूल्यांकन नहींDOMContentLoaded किया जाता
  3. यदि आप स्क्रिप्ट टैग नहीं डालते हैं तो आप निष्पादन (मूल्यांकन) में देरी कर सकते हैं (केवल इसे पहले से लोड करें link)

अब देखते हैं कुछ अन्य की सलाह नहीं दी hackey जिस तरह से आप अपने पूरे स्क्रिप्ट और जहाज है stringया comment(टिप्पणी या स्ट्रिंग के मूल्यांकन समय लगभग नगण्य है, क्योंकि) और जब आप निष्पादित करने के लिए है कि आप उपयोग कर सकते हैं की जरूरत है Function() constructorया evalदोनों की सिफारिश नहीं कर रहे हैं


एक अन्य दृष्टिकोण सेवा कार्यकर्ता: (यह पेज पुनः लोड होने के बाद आपको कैश ईवेंट को संरक्षित करेगा या कैश लोड होने के बाद उपयोगकर्ता ऑफ़लाइन हो जाएगा)

आधुनिक ब्राउज़र में आप service workerएक संभोग (जावास्क्रिप्ट, छवि, सीएसएस कुछ भी) प्राप्त करने और कैश करने के लिए उपयोग कर सकते हैं और जब उस पुनरावृत्ति के लिए मुख्य सूत्र अनुरोध आप उस अनुरोध को रोक सकते हैं और इस तरह से कैश से पुनरावृत्ति वापस कर सकते हैं जब आप स्क्रिप्ट को पार्स और मूल्यांकन नहीं कर रहे हों। आप इसे कैश में लोड कर रहे हैं, यहां सेवा कर्मचारियों के बारे में अधिक पढ़ें

उदाहरण

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
      });
    }
  }));
});

जैसा कि आप देख सकते हैं कि यह एक वेबपैक निर्भर बात नहीं है यह वेबपैक के दायरे से बाहर है, हालांकि वेबपैक की मदद से आप अपने बंडल को विभाजित कर सकते हैं जो सेवा कार्यकर्ता का बेहतर उपयोग करने में मदद करेगा


लेकिन फिर भी मेरा दर्द बिंदु यह है कि मैं वेबपैक से आसानी से फ़ाइल का यूआरएल नहीं प्राप्त कर सकता, यहां तक ​​कि मैं एसडब्ल्यू के साथ जाता हूं, मुझे अभी भी एसडब्ल्यू को यह बताने की जरूरत है कि क्या फाइलें प्री-कैश होनी चाहिए ... एक वेबपैक मैनिफ़ेस्ट प्लगइन प्रकट जानकारी उत्पन्न कर सकता है दप, लेकिन यह सब एक ऑपरेशन में है, इसका अर्थ है कि SW के पास कोई विकल्प नहीं है लेकिन प्री-कैश सभी फाइलों को जो मेनिफ़ेस्ट में सूचीबद्ध हैं ...
माइग्रोडर

आदर्श रूप से, मुझे उम्मीद है कि webpack एक और जादुई टिप्पणी जोड़ सकता है जैसे / * webpackOnlyPrefetch: true * /, इसलिए मैं हर आलसी लोड करने योग्य चंक के लिए दो बार आयात विवरण कह सकता हूं, एक प्रीफैच के लिए, एक कोड मूल्यांकन के लिए, और सब कुछ मांग पर होता है।
माइगोडर

1
@migcoder एक वैध बिंदु है (आप फ़ाइल नाम प्राप्त नहीं कर सकते क्योंकि यह गतिशील रूप से रनटाइम पर उत्पन्न होता है) किसी भी समाधान में दिखेगा यदि मुझे कोई मिल जाए
त्रिपुरारी शंकर

@migcoder मैंने उत्तर अपडेट किया है कृपया इसे देखें जो आपकी समस्या को हल करता है
त्रिपुरारी शंकर

यह समस्या का हिस्सा हल करता है, यह async चंक्स को फ़िल्टर कर सकता है जो अच्छा है, लेकिन मेरा अंतिम लक्ष्य केवल async चूजों की मांग करना है। मैं वर्तमान में इस प्लगइन को देख रहा हूँ github.com/sebastian-software/babel-plugin-smart-webpack-import , यह मुझे दिखाता है कि सभी आयात विवरणों को कैसे इकट्ठा किया जाए और जादू की टिप्पणियों पर कुछ कोड संशोधन आधार किया जाए, शायद मैं बना सकूं 'webpackOnlyPrefetch: true' मैजिक कमेंट के साथ इंपोर्ट स्टेटमेंट पर प्रीफच कोड डालने के लिए एक समान प्लगइन।
माइगोडर

1

अपडेट: मैं एक npm पैकेज में सभी चीजों को शामिल करता हूं, इसे जांचें! https://www.npmjs.com/package/webpack-prefetcher


कुछ दिनों के शोध के बाद, मैं एक अनुकूलित बाबेल प्लगइन लिखने के साथ समाप्त होता हूं ...

संक्षेप में, प्लगइन इस तरह काम करता है:

  • कोड में सभी आयात (args) कथनों को इकट्ठा करें
  • यदि आयात (args) में / * प्रीफ़ैच: ट्रू * / टिप्पणी शामिल है
  • आयात () विवरण से chunkId का पता लगाएं
  • इसे Prefetcher.fetch (chunkId) से बदलें

प्रीफ़ैचर एक सहायक वर्ग है जिसमें वेबपैक आउटपुट का प्रकटन होता है, और प्रीफ़च लिंक डालने में हमारी मदद कर सकता है:

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)
  }
}

एक उपयोग उदाहरण:

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

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

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

इस प्लगइन का विस्तार यहाँ पाया जा सकता है:

Prefetch - वेबपैक से नियंत्रण रखें

फिर से, यह वास्तव में हैक करने का तरीका है और मुझे यह पसंद नहीं है, अगर आप चाहते हैं कि वेबपैक टीम इसे लागू करे, तो कृपया यहाँ वोट करें:

फ़ीचर: मांग पर डायनेमिक आयात प्रीफ़ैच


0

यह मानते हुए कि आप जो हासिल करने की कोशिश कर रहे हैं, आप दिए गए इवेंट के बाद एक मॉड्यूल को पार्स और निष्पादित करना चाहते हैं (उदाहरण के लिए एक बटन पर क्लिक करें)। आप बस उस घटना के अंदर आयात विवरण डाल सकते हैं:

element.addEventListener('click', async () => {
  const module = await import("...");
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.