Практика оптимизации веб-пакета, разумный подпакет, сокращение времени белого экрана 👆

Webpack

предисловие

В процессе упаковки webpack часто бывает так, что файл app.js занимает несколько мегабайт, это первый файл, загружаемый на веб-страницу, из-за порядка выполнения сверху вниз предыдущий скрипт будет блокировать отрисовку страницы при загрузка, в результате белый экран.От этого идет время. Итак, как нам улучшить скорость рендеринга веб-страниц? Один из способовРазумная стратегия субподряда.

Обзор проекта

штамп источникаGitHub, предварительный просмотркликните сюда

Простой проект блога, сам проект не большой, но взгляд на суть через явление все же может объяснить некоторые проблемы.

эталонный модуль

Vue-Cli4 (аналогично 3), пользовательский интерфейс использует компонент iview, в дополнение к использованию highlight.js для выделения блоков кода, маркированной библиотеки для преобразования синтаксиса уценки, jquery и других внешних библиотек. Без какой-либо оптимизации ситуация с субподрядом показана на рисунке ниже.

分包示意图

Крупные вендоры занимают 90% экрана, а общий размер проекта почти равен размеру вендоров, обычно топовых. Остальные 10% — это почти весь jquery, а собственный код занимает менее 5% объема. Это по-прежнему код, созданный в производственной среде. Если вам интересно, вы можете запустить среду разработки на сервере, и вы узнаете, насколько медленно она загружается. 30-секундное время белого экрана не является ударом.

начать оптимизацию

настроить внешние

Параметр externals webpack подходит для следующих ситуаций: когда мы используем внешние библиотеки, такие как jquery, глобально создается пространство имен с ($) для хранения соответствующих методов, vue (Vue), vue-router (VueRouter), element -ui(ELEMENT) и так далее, вот что это значит.

Обычно мы используем только несколько методов библиотеки, и явно нецелесообразно упаковывать их все в продакшн-окружение, в это время мы можем настроить внешние, чтобы веб-пакет игнорировал эти библиотеки при упаковке и автоматически монтировал соответствующие глобальные библиотеки глобальных переменных. Вы можете импортировать конкретную библиотеку через CDN, чтобы зависимости можно было извлечь и загрузить позже. Например:

/**
 * vue.config.js
 */
configureWebpack: config => {
    config.externals = {
        marked: 'marked',
        jquery: '&',
        // 这里要注意,键名就是npm包名,值就是库对应的全局变量
        // 如果有特殊符号最好用引号包起来,例如:
        'highlight.js': 'hljs'
    }
  }
}

Давайте посмотрим на эффект ниже:

externals效果

Видно, что эффект налицо, jquery пропал, highlight.js пропал, и mark пропал. вендоры от 1м => 300кб, а дальше мы можем импортировать эти библиотеки внизу html:

html中引入对应CDN

Поскольку highlight.js немного трудоемок для выделения кода, я поместил эту часть контента в WebWorker для реализации, поэтому соответствующий CDN помещается в вейкер и импортируется с помощью importScript, поэтому я не буду вдаваться в подробности. здесь.

Эффект все равно виден. Но есть еще возможности для улучшения.

Примечание. Размещение внизу страницы может ускорить отрисовку страницы при условии, что эти библиотеки не требуются для инициализации страницы. В противном случае страница инициализации приведет к ошибке неопределенной переменной.

Поскольку все страницы семейства Bucket vue, vue-router и другие страницы необходимо использовать сразу после их загрузки, даже если они заменены CDN, их необходимо размещать в верхней части страницы. главным образом потому, что это все еще очень хлопотно, поэтому для таких необходимых зависимостей я использую другой способ.

Настройте параметр cacheGroups

Давайте сначала посмотрим на конфигурацию по умолчанию, встроенную в скаффолдинг, запущенную в корневом каталоге проекта.vue uiВойдите в выбор визуального интерфейсаinspectВыполнение задачи:

ui管理界面

Найдите соответствующую конфигурацию следующим образом:

optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          name: 'chunk-vendors',
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          chunks: 'initial'
        },
        common: {
          name: 'chunk-common',
          minChunks: 2,
          priority: -20,
          chunks: 'initial',
          reuseExistingChunk: true
        }
      }
    }
}

CacheGroups буквально означает группы кеша, но на самом деле определяет правила субдоговора Эти зависимости извлекаются в модуль при выполнении условий, что является ключевой конфигурацией splitChunks. Вот как webpack определяет, как разделить модули.

Как вы можете видеть выше, поставщики используют тестовую опцию для регулярного сопоставления, чтобы упаковать все зависимости, используемые в node_modules, в модуль с именем chunk-vendors.

Возможно, вам придется спросить, jquery тоже есть в node_modules, почему бы и нет в vendors. Поскольку я ссылаюсь на него в компоненте, он упакован вместе с компонентом.

Предположим, что следующий ссылочный оператор встречается более чем в двух компонентах:

import $ from 'jquery'

Затем он будет соответствовать второму общему правилу (minChunks равно 2), будет извлечен и упакован в файл с именем chunk-common. Что касается случая, когда соблюдаются несколько правил одновременно, приоритет используется для установки веса и решения, кого слушать.

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

Слишком много или слишком мало модулей — это нехорошо, это не может быть так экстремально. Их сбор вместе уменьшает количество запросов, а их разделение ускоряет загрузку, но в то же время первое увеличивает время загрузки, а второе увеличивает время, необходимое для установления и разрыва соединения. Все за и против нужно взвешивать в каждом конкретном случае.

Как правило, модули, которые использовались ранее, загружаются первыми. В этом проекте я разделил зависимости на:

  1. семейное ведро vue
  2. Компоненты пользовательского интерфейса
  3. другие зависимости

Конфигурация выглядит следующим образом:

/**
 * vue.config.js
 */
configureWebpack: config => {
    Object.assign(config.optimization.splitChunks.cacheGroups, {
      'view-design': { // 分离组件库
        name: true, // name 为true会自动命名
        test: /[\\/]view-design[\\/]/,
        priority: 10,
        chunks: 'initial'
      },
      vue: { // 分离vue全家桶
        name: true,
        test: /[\\/]vue(.+?)[\\/]/,
        priority: 5,
        chunks: 'initial'
      }
    })
  }
}

Правила обработки для других зависимостей — это предопределенные поставщики и общие, которые я не менял.

最终结果

数据

На самом деле, это почти там. Смысл субподряда заключается в повышении эффективности передачи, а не в сокращении объема.

разное

Внедрить по требованию

Например, библиотеки компонентов, такие как lodash и moment, снабжены соответствующими подключаемыми модулями веб-пакетов, которые можно импортировать по запросу, а также можно соответствующим образом использовать внешние компоненты. Некоторые библиотеки компонентов, такие как element-ui, iview и т. д., можно импортировать по запросу с помощью babel-plugin-import, и в официальных документах есть соответствующие инструкции. После введения по требованию нет необходимости использовать внешние, да и лично я считаю это ненужным.

О CDN

Поскольку одновременные запросы под одним и тем же доменным именем ограничены браузером, некоторые из них имеют 4 или 6, а разные браузеры кажутся разными, поэтому при внедрении множества CDN вы можете рассмотреть возможность использования разных исходных сайтов, вот два рекомендуемых:

  1. Внешняя библиотека статических ресурсов
  2. staticfile CDN

ты говоришьBootCDN? Как бы это сказать, сначала у меня сложилось хорошее впечатление о bootCDN, и мне понравился интерфейс. Позже я обнаружил, что CDN работает нестабильно и часто недоступен. Я думал, что это проблема проекта. что CDN не был успешно внедрен. Не то, чтобы его нельзя было использовать, маленькое демо все же можно написать

О DllPlugin

Если вам не интересно, можете пропустить это

Недавно я использовал его для выполнения функции, похожей на приведенную выше группу cacheGroup.На самом деле, я впервые узнал о cacheGroup после DllPlugin. Из-за того, что конфигурация немного громоздкая, я подумал, что я был потрясающим после того, как изучил ее, но позже я узнал, что этот плагин устарел. Как бы это сказать, я немного растерялся, ведь я долго учился.

Но подумайте хорошенько, когда через webpack3, через этот плагин можно упаковать часто используемые, но не часто изменяемые библиотеки и напрямую импортировать их в html, такие как vue, vue-router, vuex и т.д. Но позже я узнал, что когда он его упаковывал, то вводил все это, если он встретит библиотеку компонентов, то упакует многое из этого.

Изначально этот плагин использовался для ускорения сборки, так как не нужно было каждый раз компилировать статические ресурсы. Однако из-за необходимости писать дополнительную конфигурацию веб-пакета, а конфигурация получается относительно громоздкой. Хотя есть плагины автоматизации, но они не выдерживают изменения времени. Теперь, когда идет webpack5, скорость создания webpack полностью в порядке, и если вы можете использовать cacheGroups для субподряда, в этом нет необходимости.

Какой? Зачем писать это, если оно устарело? Потому что я расстроен 🤬, мне неудобно, у меня психологический разрыв, ха-ха, я хочу это записать.

наконец

Сейчас я стесняюсь сказать, что занимаюсь фронтендом без вебпака. В последнее время я написал много демок и столкнулся с множеством проблем, которые помогли мне лучше понять webpack. Я всегда хотел написать статью, чтобы обобщить ее, но проблемы, с которыми я столкнулся, были очень фрагментарными, и казалось, что я не смогу написать статью, наконец, у меня появилась такая возможность.

Если вы думаете, что это хорошо после прочтения, не забудьте поставить лайк, спасибо 😄

связанные ресурсы

  1. Внешняя библиотека статических ресурсов
  2. staticfile CDN
  3. BootCDN
  4. Исходный код на гитхабе
  5. Оптимизация внешнего интерфейса: используйте dll для извлечения сторонних js (DllPlugin DllReferencePlugin)