SplitchunksPlugin разборки и разборки webpack4 -- проектная практика

внешний интерфейс JavaScript React.js ECharts
SplitchunksPlugin разборки и разборки webpack4 -- проектная практика

В этой статье объясняется процесс разделения пакета кода в сочетании с splitChunks webpack4 для многостраничного проекта, над которым я недавно работал.

рамки проекта

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

  • react, mobx, antd используются как базовый фреймворк проекта,
  • echarts (живопись) и d3 (живопись) — относительно большие библиотеки компонентов, используемые некоторыми страницами проекта.
  • src код общего компонента проекта и т. д.
  • Другой закрытый код.

Оба входных файла загружаются асинхронно с помощью react-loadable

import Loadable from 'react-loadable';
...
const LoadableLogin = Loadable({
  loader: () => import('../../common/components/login'),
  loading: Loading,
});
...

Некоторые конфигурации веб-пакета следующие:

module.exports = {
  ...
  mode: 'production',
  entry: { // 多入口
    home: './src/home',
    topic: './src/topic',
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
  },
  plugins: [
    new HtmlWebpackPlugin({ // home页面
      filename: 'home.html',
      template: './template.html',
    }),
    new HtmlWebpackPlugin({ // topic页面
      filename: 'topic.html',
      template: './template.html',
      inject: true,
    }),
  ],
  ...
}
  

splitChunks

chunks:

  • все: независимо от того, загружается ли файл динамически или нет, файлы равномерно разделены. Все пакеты импортируются при первой загрузке страницы
  • async: разделите асинхронно загружаемые файлы, обычно не вводимые в первый раз, до компонентов, которые необходимо импортировать асинхронно.
  • Initial: разделяет асинхронные и неасинхронные файлы.Если файл импортируется асинхронно и неасинхронно, он будет упакован дважды (обратите внимание на отличие от всех), чтобы отделить пакет, который страница должна загрузить в первый раз.

minSize: минимальный размер пакета файла в байтах, по умолчанию 30000.

Например, есть три входных файла под неким проектом, a.js, b.js и c.js все по 100 байт, когда мы установим minSize в 301, то webpack упакует их в один пакет и не будет их дизассемблировать. несколько пакетов.

AutomaticNameDelimiter: Соединитель

Предположим, мы создаем общий файл с именем vendor, a.js и b.js зависят от него, а коннектор, который мы установили, равен «~», тогда окончательный сгенерированный файл будет vendor~a~b.js.

maxInitialRequests Максимальное количество параллельных запросов в точке входа, по умолчанию 3

Если мы установим его равным 1, то каждый файл записи будет упакован только в один файл.

maxAsyncRequests максимальное количество асинхронных запросов, по умолчанию 5

Если мы установим его равным 1, то каждый файл записи будет упакован только в один файл.

приоритетное отношение

maxInitialRequest / maxAsyncRequests

cacheGroups настраивает правила разделения пакетов

test может настраивать обычные функции и функции записи в качестве правил упаковки. Другие свойства могут наследовать splitChunks, о чем здесь нужно сказать.приоритет, установите приоритет упаковки пакета, очень важно!(в сочетании с практикой позже)

minChunks

Минимальное количество знакомств

упражняться

Начнем с самой простой конфигурации, котораяобщедоступный кодупаковать его

   splitChunks: {
      chunks: 'all',   // initial、async和all
      minSize: 30000,   // 形成一个新代码块最小的体积
      maxAsyncRequests: 5,   // 按需加载时候最大的并行请求数
      maxInitialRequests: 3,   // 最大初始化请求数
      automaticNameDelimiter: '~',   // 打包分割符
      name: true,
      cacheGroups: {
        vendors: { // 打包两个页面的公共代码
          minChunks: 2, // 引入两次及以上被打包
          name: 'vendors', // 分离包的名字
          chunks: 'all'
        },
      }
    },

Общий код двух входных файлов упакован в папку поставщика, включая некоторые сторонние пакеты, такие как echarts d3 amcharts и общий код в src.

Это точно не тот результат, который нам нужен! Существуют следующие проблемы:

  • На самом деле, когда мы заходим на сайт, первым шагом является вход на целевую страницу.Все, что нам нужно, это базовый код фреймворка проекта, такой как react, react-dom.antd и т. д. Мы можем использовать все (или начальные ), чтобы упаковать их отдельно как пакеты, которые должны быть загружены на домашнюю страницу

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

  • Например, echarts, d3 и некоторые ниже srcАсинхронная загрузкапакеты, используйте async для их упаковки в один асинхронно загружаемый пакет

Мы модифицируем cacheGroups на:

   cacheGroups: {
        vendors: { // 项目基本框架等
          chunks: 'all',
          test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
          priority: 100,
          name: 'vendors',
        },
        'async-commons': {  // 异步加载公共包、组件等
          chunks: 'async',
          minChunks: 2,
          name: 'async-commons',
          priority: 90,
        },
        commons: { // 其他同步加载公共包
          chunks: 'all',
          minChunks: 2,
          name: 'commons',
          priority: 80,
        },
      }

Пакеты, которые Webpack помог нам набрать на этот раз, в основном включают:

  • async-common: это трехсторонний пакет, в котором оба входных файла загружаются асинхронно, а код отложенной загрузки, созданный react-loader, включая echarts, d3 и т. д.

  • поставщики: включая реакцию, реакцию-дом, антд и т. д.

  • Commons: синхронный код ссылается более чем в два раза

Вот две вещи, на которые следует обратить внимание:

  • Обратите внимание на настройку нашего приоритета здесь, vendors>async-commons>commons, мы сначала упаковываем react, react-dom и т. д., а затем упаковываем публичную часть,Если приоритет вендоров установлен меньше, чем приоритет двух общих, то react, react-dom будут упакованы в общий пакет, а пакет вендоров не будет генерироваться повторно.

  • Если мы удалим здесь конфигурацию commons, будет сгенерирован пакет theme~home, и мы настроили async-commonПосле извлечения асинхронно загруженного общедоступного пакета синхронно загруженный общедоступный пакет будет упакован по умолчанию.Создайте пакет имени «topic~home», сгенерированный соединителем AutomaticNameDelimiter «~», содержимое которого фактически совпадает с содержимым пакета commons.точно так же,

Ok! Согласно нашим требованиям, при загрузке первой страницы будут представлены только пакеты vendors и commons, а пакет async-common не будет представлен, что все равно здорово! Для тех из нас, кто стремится к большему совершенствованию, если мы тщательно обдумаем это, можем ли мы сделать некоторые оптимизации получше?

Упаковка наших упаковочных файлов на данный момент выглядит следующим образом:

После gzip самый большой пакет async-common весит 391 КБ. Компания заявила, что из-за некоторых обстоятельств в последнее время, когда макет после производства работает медленно, иногда скорость загрузки может составлять всего 20 кбит/с ==. . . . Так что продолжайте разделять!

Проанализируйте это:

  • async-common включает компоненты src и сторонние компоненты, написанные вами

  • Более крупными в async-common являются echarts, zrender (введенный echarts) и d3.С точки зрения проектов, толькочасть страницыНам нужны echarts (такие же, как d3), поэтому мы можем рассмотреть возможность извлечения двух более крупных пакетов, d3 и echarts, и позволить им загружаться асинхронно, когда это необходимо странице, что значительно снижает общий асинхронный объем.

Исправлять

    cacheGroups: {
        vendors: { // 基本框架
          chunks: 'all',
          test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
          priority: 100,
          name: 'vendors',
        },
        d3Venodr: { // 将体积较大的d3单独提取包,指定页面需要的时候再异步加载
          test: /d3/,
          priority: 100, // 设置高于async-commons,避免打包到async-common中
          name: 'd3Venodr',
          chunks: 'async'
        },
        echartsVenodr: { // 异步加载echarts包
          test: /(echarts|zrender)/,
          priority: 100, // 高于async-commons优先级
          name: 'echartsVenodr',
          chunks: 'async'
        },
        'async-commons': { // 其余异步加载包
          chunks: 'async',
          minChunks: 2,
          name: 'async-commons',
          priority: 90,
        },
        commons: { // 其余同步加载包
          chunks: 'all',
          minChunks: 2,
          name: 'commons',
          priority: 80,
        },
      }

Разумеется, после каждой модификации нужно настраивать пакеты, требуемые по чанку в htmlWebpackPlugin.

  plugins: [
    new HtmlWebpackPlugin({ // home页面
      filename: 'home.html',
      template: './template.html',
      chunks: ['vendors', 'commons', 'home'],
    }),
    new HtmlWebpackPlugin({ // topic页面
      filename: 'topic.html',
      template: './template.html',
      chunks: ['vendors', 'commons', 'topic'],
    }),
  ],

На более позднем этапе также были сделаны другие разбиения и оптимизации.Вероятно, самый большой пакет хранится около 100 КБ.Конечно, не рекомендуется разбивать его на особенно маленький размер, потому что браузер http1 может поддерживать 6 загрузок файлов на время, слишком много может быть контрпродуктивным. Вы можете использовать различные методы разделения в соответствии с вашим собственным проектом.В целом, это должно сделать проект более совершенным в Интернете и предоставить пользователям лучший опыт~