В веб-пакете, как я могу импортировать скрипт без его оценки? - PullRequest
9 голосов
/ 21 января 2020

Я недавно работаю над оптимизацией веб-сайта и начинаю использовать разбиение кода в веб-пакете, используя следующую инструкцию импорта:

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

, которая правильно создает pageB-chunk. js, теперь допустим, что я хочу предварительную выборку этого фрагмента на странице A, я могу сделать это, добавив следующее утверждение на странице A:

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

, что приведет к добавлению

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

к голове HTML, тогда браузер будет предварительно выбирать его, пока все хорошо.

Проблема в том, что оператор import , который я здесь использую, не только предварительно выбирает файл js, но и оценивает файл js, означает, что код этого файла js анализируется и компилируется к байт-кодам, выполняется код верхнего уровня этого JS.

Это очень трудоемкая операция на мобильном устройстве, и я хочу ее оптимизировать, мне нужна только предварительная выборка 1027 * часть, я не хочу оценить и выполнить часть, потому что позже, когда какой-то пользователь взаимодействует ионы случаются, я вызову разбор и оценку сам

enter image description here

↑↑↑↑↑↑↑↑ Я только хочу инициировать первые два шага, изображения приходят с https://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/ ↑↑↑↑↑↑↑↑↑

Конечно, я могу сделать это, добавив ссылку на предварительную выборку самостоятельно, но это означает, что мне нужно Чтобы узнать, какой URL-адрес я должен добавить в ссылку предварительной выборки, веб-пакет определенно знает этот URL-адрес, как я могу получить его из веб-пакета?

Есть ли у веб-пакета простой способ добиться этого?

Ответы [ 3 ]

2 голосов
/ 30 января 2020

ОБНОВЛЕНИЕ

Вы можете использовать preload-webpack-plugin с html -webpack-plugin , это позволит вам определить, что для предварительной загрузки в конфигурации, и он автоматически вставит теги для предварительной загрузки вашего чанка

примечание, если вы используете webpack v4 на данный момент, вам придется установить этот плагин, используя preload-webpack-plugin@next

пример

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

Для проекта, генерирующего два асинхронных c сценария с динамически генерируемыми именами, такими как 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">

ОБНОВЛЕНИЕ 2

, если вы не хотите предварительно загружать весь асинхронный блок c, а только указывать c раз вы можете сделать это тоже

либо вы можете использовать плагин migcoder's babel или с preload-webpack-plugin, как в случае с

  1. сначала у вас будет назвать этот асин c чанк с помощью 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)

теперь есть некоторые другие не рекомендуемые хаккейный способ - вы отправляете весь свой сценарий и string или comment (потому что время оценки комментария или строки практически ничтожно) и когда вам нужно выполнить, что вы можете использовать Function() constructor или eval оба не рекомендуются


другой подход Сервисные работники: (это сохранит ваше кеш-событие после перезагрузки страницы или перехода пользователя в автономный режим после загрузки кеша)

* 1 084 * В современном браузере вы можете использовать service worker для извлечения и кэширования ресурса (JavaScript, изображение, css что угодно), и когда основной поток запроса для этого ресурса вы можете перехватить этот запрос и таким образом вернуть ресурс из кэша вы не анализируете и не анализируете скрипт, когда загружаете его в кеш, читайте больше о сервисных работниках здесь

пример

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

, как вы можете видеть это не зависимый от веб-пакета вещь, которая выходит за рамки веб-пакета, однако с помощью веб-пакета вы можете разделить ваш пакет, что поможет более эффективно использовать работника сервиса

1 голос
/ 04 февраля 2020

Обновления: Я включаю все вещи в npm пакет, зацените! https://www.npmjs.com/package/webpack-prefetcher


После нескольких дней исследований я заканчиваю писать плагин для настройки babel ...

Короче говоря, плагин работает следующим образом :

  • Соберите все import (args) операторов в коде
  • Если import (args) ) содержит / * предварительную выборку: true * / comment
  • Найдите chunkId из import () оператор
  • Заменить его на Prefetcher.fetch (chunkId)

Prefetcher - это вспомогательный класс, содержащий манифест вывода веб-пакета и может помочь нам при вставке ссылки предварительной выборки:

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(...)

Подробную информацию об этом плагине можно найти здесь:

Предварительная выборка - получить контроль из веб-пакета

Снова Это действительно хакерский способ, и мне не нравится, если вы хотите, чтобы команда webpack реализовала это, пожалуйста, проголосуйте здесь:

Функция: prefetch dynamici c Импорт по требованию

0 голосов
/ 03 февраля 2020

Предполагая, что я понял, чего вы пытаетесь достичь, вы хотите проанализировать и выполнить модуль после определенного события (например, нажмите на кнопку). Вы можете просто поместить оператор импорта внутри этого события:

element.addEventListener('click', async () => {
  const module = await import("...");
});
...