Разговор о SplitChunks Webpack

внешний интерфейс Webpack
Разговор о SplitChunks Webpack

На официальном сайте webpack есть такая фраза, с которой я не очень согласен:

из коробкиSplitChunksPluginОчень дружелюбен к большинству пользователей.

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

Сначала нам нужно понять концепцию.

что такое чанки

Обычный вопрос на собеседовании: что такое модули, фрагменты и пакеты. Для начинающих это очень запутанно. Сначала нам нужно знать простое понимание веб-пакета:

Webpack: создавайте свои активы. После того, как ресурсы слева проходят через веб-пакет, они могут выводить ресурсы, которые могут распознавать веб-браузеры! Это приписывается узлу, строящему мир, чтобы все не-js-ресурсы в этом мире обрабатывались по правилам js-мира:

css: по сути, это строка под стилем. После того, как webpack обработает текст css, если вы хотите вставить его непосредственно как тег стиля, используйте загрузчик стилей. Если вы хотите вынуть его, он будет обработан через Плагин MiniCssExtractPlugin. less: Суть в том, чтобы окончательно конвертировать в css, поэтому через less-loader конвертировать в css, а затем повторить вышеописанную операцию. typescript: Браузер не может напрямую распознать его через ts-loader. чтобы преобразовать его в js, который может распознать браузер.

Все вышеперечисленное для одного:

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

Файл ts, picture, less, pug и т. д. — все это модули, а упакованный продукт обычно называется комплектом.

Так что же такое чанк?

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

Попробуем упаковать!

распределение по умолчанию

Теперь мы создаем src/index.js и src/a.js

index.js a.js
import lodash from "lodash";,import { a } from "./a";,console.log(lodash, a); export const a = "i am aaaaaa";,console.log(a);,

Структура каталога:

Результаты конфигурации и упаковки webpack.config.js:

webpack.config.js
{, mode: "production",, entry: {, main: "./src/index.js",, },, output: {, path: path.resolve(__dirname, "dist"),, filename: "[name].js", , clean: true,, },,} |

По умолчанию webpack не разбивается на подпакеты, он собран вместе.

некоторые поля конфигурации

Подпакет Webpack в основном находится в свойстве Optimization.splitChunks, теперь давайте попробуем разные поля конфигурации, чтобы увидеть эффект.

optimization.splitChunks.chunks

Чанки имеют три предоставленных значения: асинхронный, начальный, все

async

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

import('lodash')

Измените index.js, а затем запустите команду сборки.Чтобы сделать файл более интуитивным, мы установили значение Optimization.chunkIds в named

index.js
import { a } from "./a";,import('lodash').then(lodash => {, const res = lodash.default.add(3,4), console.log(a, res);,})

Ниже приводится высказывание WebPack для конфигурации по умолчанию:

webpack автоматически разбивает чанки на основе следующих условий: Новые чанки могут быть общими, или модули берутся изnode_modulesпапка Размер нового фрагмента больше 20 КБ (размер до min+gz) При загрузке чанков по запросу максимальное количество параллельных запросов меньше или равно 30 При загрузке страницы инициализации максимальное количество одновременных запросов меньше или равно 30 Пытаясь удовлетворить два последних условия, лучше использовать более крупные куски.

После эксперимента выяснилось, что он неточен, например, два входа вводили лодаш, а лодаш не извлекали.

index.js other.js
import lodash from "lodash";,import { a } from "./a";,console.log(lodash, a); import lodash from "lodash";,,console.log("lodash", lodash);

Конфигурация и упаковка

настроить Пакет
{, entry: {, main: "./src/index.js",, other: "./src/other.js",, },, optimization: {, chunkIds: "named",, },,}
Конфигурация по умолчанию извлекает только динамически загруженные модули.Обычно пакеты, которые не нужны немедленно, могут быть динамически загружены, например, пакеты, которые экспортируют excel, echarts, monaco-editor и т. д.
#### initial

Когда чанк является начальным или полным, упаковка веб-пакета следует следующей конфигурации (названной по умолчанию):

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'initial',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

Хотя ваш конфиг может выглядеть так:

{, entry: {, main: "./src/index.js",, other: "./src/other.js",, },, optimization: {, chunkIds: "named",, splitChunks: {, chunks: "initial",, },, },,}

Только когда кусочки не асинхроны, WebPack упаковывает конфигурацию по умолчанию, является конфигурацией по умолчанию

Новые фрагменты могут быть общими, или модули могут быть взяты изnode_modulesпапка Размер нового фрагмента больше 20 КБ (размер до min+gz) При загрузке чанков по запросу максимальное количество параллельных запросов меньше или равно 30 При загрузке страницы инициализации максимальное количество одновременных запросов меньше или равно 30

all

import('lodash').then(lodash => {
    const res = lodash.default.add(3,4)
    console.log(res);
})

all initial

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

Другие конфигурации по умолчанию для optimization.splitChunks

{
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
}

minSize: эта конфигурация означает, что если фрагменты, подлежащие разбиению, меньше 20 КБ перед сжатием, они не будут распаковываться. minChunks: на фрагмент ссылаются несколько раз. Если счетчик ссылок меньше определенного значения, он не будет распакован. ... Одно из вышеуказанных условий будет субподрядным. EnforceSizeThreshold: если размер чанка превышает 50 КБ, вышеуказанное ограничение не вступит в силу.

optimization.splitChunks. cacheGroups

Есть две стратегии кэширования по умолчанию для cacheGroups, то есть конфигурация по умолчанию, когда куски собраны целиком и полностью:

cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
 }

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

// index.js
import lodash from "lodash";
import { a } from "./a";
import { b } from "./b";
console.log(lodash, a, b);

// a.js
export const a = "i am aaaaaa";
console.log(a);
import "./c";

// b.js
export const b = "i am bbbbbbbbb";
console.log(b);
import "./c";

// c.js
console.log("ccccccccc");

a.js и b.js ссылаются на c.js вместе. В настоящее время a, b и c подчинены записи index.js. Хотя c.js упоминается дважды, c.js не будет разделен на отдельные пакеты. Если вы хотите упаковать c.js отдельно, рассмотрите возможность динамическая загрузка.

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

react: {
  name: "ReactAbout",
  test: /react/,
  priority: 1,
},

Эффект упаковки

// other.js

import('lodash').then(lodash => {
    const res = lodash.default.add(3,4)
    console.log(res);
})

import('./style/a.css')
import('./style/b.css')
import('./style/c.css')
{
    test: /\.css$/,
    use: ["style-loader", "css-loader"],
}

css

CSS также является частью оптимизации производительности.Один из способов — вставить CSS в документ в виде тегов стиля через загрузчик стилей. Таким образом, обычные ссылки не могут быть разделены на подпакеты. Но это может быть передано на субподряд посредством динамического внедрения.

Кроме того, есть плагин MiniCssExtractPlugin для подпакета css. По умолчанию этот плагин извлекает css отдельно для каждой записи, а также может настраивать cacheGroups.При выполнении условий css нескольких записей будет упакован вместе.

css: {
  name: "css",
  test: /\.css$/,
  minChunks: 1,
  enforce: true,
}