Webpack4 SplitChunks детально реализует разделение кода

Webpack

код помещается вgit-репозиторий

Webpack 4 приносит нам некоторые изменения. Включая более быструю упаковку, плагин SplitChunksPlugin был представлен для замены плагина CommonsChunksPlugin (в предыдущих версиях). В этом посте вы узнаете, как разделить выходной код, чтобы повысить производительность нашего приложения.

SplitChunksплагин (webpack 4.x以前使用CommonsChunkPlugin) позволяет нам извлечь общие зависимости к существующемуentry chunkили в совершенно новом блоке кода.

Концепция разделения кода

Сначала поймите: что, черт возьми, такое разделение кода в веб-пакете? Это позволяет разделить файл на несколько файлов. При правильном использовании он может значительно повысить производительность вашего приложения. Причина этого заключается в том, что браузер кэширует ваш код. Каждый раз, когда вы вносите изменения в файл, людям, посещающим ваш сайт, придется загружать его снова. Однако зависимости редко меняются. Если вы разделите (эти зависимости) на отдельные файлы, посетителям не придется загружать их несколько раз.

Используйте webpack для создания одного или нескольких «упакованных файлов», содержащих окончательную версию вашего исходного кода (bundles), (концептуально берем) состоят из (одного за другим)chunksсочинение.

Прежде всего, webpack предоставляет три способа реализации разделения кода, а именно:

  • Конфигурация записи: запись записи использует несколько файлов записей;
  • Извлечение общедоступного кода: используйте SplitChunks для извлечения общедоступного кода;
  • Динамическая загрузка: Динамическая загрузка некоторого кода.

Здесь мы обсуждаем только использование SplitChunks для извлечения общедоступного кода.

Конфигурация splitChunks

Создайте три файла pageA.js, pageB.js и pageC.js в каталоге src. Подробнее о коде см. в репозитории git в начале статьи.

// src/pageA.js
var react = require('react');
var reactDom = require('react-dom');
var utility1 = require('../utils/utility1');
var utility2 = require('../utils/utility2');
new Vue();

module.exports = "pageA";
// src/pageB.js
var react = require('react');
var reactDom = require('react-dom');
var utility2 = require('../utils/utility2');
var utility3 = require('../utils/utility3');

module.exports = "pageB";
// src/pageC.js
var react = require('react');
var reactDom = require('react-dom');
var utility2 = require('../utils/utility2');
var utility3 = require('../utils/utility3');

module.exports = "pageC";

импортировать файл && экспортировать файл

entry: {
    pageA: "./src/pageA",    // 引用utility1.js  utility2.js
    pageB: "./src/pageB",    // 引用utility2.js  utility3.js
    pageC: "./src/pageC",   // 引用utility2.js  utility3.js
},
output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].[hash:8].bundle.js"
},

Настроить оптимизацию

Сначала мы настраиваем оптимизацию следующим образом:

optimization: {
    splitChunks: {
      chunks: "all",
  },

После выполнения команды сборки сборки npm run просмотрите каталог dist

image.png

Можно обнаружить, что в дополнение к упакованным трем файлам страниц имеется также файл vendor~pageA~pageB~pageC.[hash].bundle.js (Этот файл сохраняет файлы размером более 30 КБ в page, page, page и node_modules.). На самом деле все зависит от дефолтного пункта конфигурации cacheGroups в конфигурации:

splitChunks: {
    chunks: "all",
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,  // 匹配node_modules目录下的文件
        priority: -10   // 优先级配置项
      },
      default: {
        minChunks: 2,
        priority: -20,   // 优先级配置项
        reuseExistingChunk: true
      }
    }
  }

В настройках по умолчанию

  • упакует модули в папке node_mudules в пакет с именем vendors,
  • Все модули, ссылающиеся более чем в два раза, присваиваются на пучок по умолчанию Вы также можете установить приоритет через приоритет.

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

  • Чанки: указывает, из каких фрагментов извлекать код.В дополнение к трем необязательным строковым значениям: начальный, асинхронный и все, требуемые фрагменты также можно фильтровать с помощью функций;
  • минРазмер:Указывает минимальный размер извлекаемого файла перед сжатием, по умолчанию 30000.;
  • maxSize: указывает максимальный размер извлекаемого файла перед сжатием, по умолчанию 0, что означает, что максимальный размер не ограничен;
  • мин куски:Указывает количество цитирований, по умолчанию 1; MinChunks в общих ресурсах конфигурации выше равен 2, что означает, что код, на который ссылаются много раз, будет извлечен в общие ресурсы.

Стоит отметить, что если свойство minSize не изменено, а размер общего кода (при условии, что tools.js) меньше 30 КБ, он не будет разбит на отдельный файл. В реальной ситуации это разумно, т.к. (типа разбиения) не приводит к реальному улучшению производительности, а вместо этого делает браузеру еще один запрос на tools.js, который такой маленький (не рентабельный).

  • maxAsyncRequests: максимальное количество загрузок по запросу (асинхронных), по умолчанию — 5;
  • maxInitialRequests: максимальное количество начальных загрузок, по умолчанию 3;
  • AutomaticNameDelimiter: разделитель автоматически сгенерированного имени извлеченного файла, по умолчанию ~;
  • имя: имя извлеченного файла, по умолчанию true, что означает, что имя файла генерируется автоматически;
  • cacheGroups: группы кэширования. (Это ключ к настройке)

Группы кэша наследуют конфигурацию splitChunks, ноtest, priority и reuseExistingChunk можно использовать только для настройки групп кеша.. cacheGroups — это объект, который можно настроить в соответствии с описанным выше методом пары ключ-значение, а значение представляет соответствующую опцию. Кроме того, все перечисленные выше параметры доступны в группах кеша: chunks, minSize, minChunks, maxAsyncRequests, maxInitialRequests, name. Группу кеша по умолчанию можно отключить с помощью оптимизации.splitChunks.cacheGroups.default: false.Приоритет группы кеша по умолчанию отрицательный, поэтому все пользовательские группы кеша могут иметь более высокий приоритет, чем он. Приоритет группы равен 0)

Теперь давайте снова посмотрим на три js-файла pageA, pageB и pageC.В этих трех файлах присутствует файл Utility2.js, но размер этого файла явно меньше 30Кб, поэтому эта часть общего кода не делится . Если вы хотите разделить это очень просто, просто нужно:

optimization: {
    splitChunks: {
      chunks: "all",
      minSize: 0
    }
},

После выполнения команды сборки сборки npm run просмотрите каталог dist

image.png

Очевидно, есть еще один файл pageA~pageB~pageC.[hash].bundle.js. Глядя на файл, вы можете видеть, что код вutility2.js хранится в этом файле. Как показано на рисунке ниже (с помощью плагина webpack-bundle-analyzer, подробности в приложении в конце статьи).

image.png

Как видно из рисунка выше, код, связанный с React, находится в файле vendors~pageA~pageB~pageC.[hash].bundle.js Если мы хотим извлечь код React, что нам делать?

splitChunks: {
      chunks: "all",
      cacheGroups: {
        commons: {
          chunks: "initial",
          minChunks: 2,
          name: "commons",
          maxInitialRequests: 5,
          minSize: 0, // 默认是30kb,minSize设置为0之后
                            // 多次引用的utility1.js和utility2.js会被压缩到commons中
        },
        reactBase: {
          test: (module) => {
            return /react|redux|prop-types/.test(module.context);
          }, // 直接使用 test 来做路径匹配,抽离react相关代码
          chunks: "initial",
          name: "reactBase",
          priority: 10,
        }
    }
},

После запуска сборки это показано на следующем рисунке.

image.png

приложение

Установим еще один webpack-bundle-analyzer, этот плагин будет четко отображать модули, от которых зависят упакованные бандлы:

npm i webpack-bundle-analyzer -D

Представлять:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

Чтобы использовать, добавьте его в массив плагинов:

new BundleAnalyzerPlugin()