оптимизация упаковки webpack4 (HappyPack, загрузчик потоков)

Webpack

1. Анализ скорости

Установите плагин speed-measure-webpack-plugin

npm install --save-dev speed-measure-webpack-plugin

Внедрение подключаемых модулей, создание подключаемых объектов

const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); //引入插件
const smp = new SpeedMeasurePlugin(); //创建插件对象

Используйте метод плагина wrap() для переноса конфигурации

module.exports = smp.wrap({
  entry: {
    index: './src/index.js',
    search: './src/search.js',
  }, 
  output: {
    path: path.join(__dirname, 'dist'), //__dirname(当前模块的目录名) + dist
    filename: '[name]_[chunkhash:8].js', //打包后输出的文件名,添加文件指纹 chunkhash
  },
plugpins: [],
.....
});

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

2. Объемный анализ

Какие проблемы может анализировать объемный анализ?

  1. Зависимый размер файла стороннего модуля
  2. Размер кода компонента в бизнесе

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

Установите плагин webpack-bundle-analyzer.

npm install --save-dev webpack-bundle-analyzer

Внедрение подключаемых модулей, создание подключаемых объектов

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

Добавить конфигурацию плагинов

 plugins: [
    new BundleAnalyzerPlugin()
  ],

После того, как пакет завершится, откроется браузерhttp://127.0.0.1:8888/Показать анализ упакованного объема

image.png

3. Оптимизация скорости упаковки

Процесс построения веб-пакета напрямую влияет на эффективность построения, один — это компиляция файлов, а другой — классификация и упаковка файлов. Напротив, компиляция файлов требует больше времени, а в среде Node файлы могут обрабатываться только один за другим, поэтому эту оптимизацию необходимо решить. Так как же оптимизировать скорость упаковки?

1. Используйте более позднюю версию webpack и node.js

Оптимизация новой версии webpack4 использует движок v8, а оптимизация, внесенная v8, включает

  • for заменяет forEach
  • Карта и набор вместо объекта
  • включает заменяет indexOf()
  • По умолчанию используйте более быстрый алгоритм хеширования md4 вместо алгоритма md5, md4 быстрее, чем md5.
  • Webpack AST может быть передан непосредственно из загрузчика в AST, что сокращает время синтаксического анализа.
  • Используйте строковые методы вместо регулярных выражений

более поздняя версияnode.jsДальнейшая оптимизация нативного js API и структуры данных js

2. Многопроцессное/многоэкземплярное построение (параллельный анализ ресурсов)

В процессе создания веб-пакета нам нужно использовать Loader для преобразования js, css, изображений, шрифтов и других файлов, и объем преобразованных файловых данных также очень велик, и эти операции преобразования не могут обрабатывать файлы одновременно, а требуют файлы один за другим. one Для обработки нам нужно разложить эту часть задачи на несколько подпроцессов для параллельной обработки.После обработки подпроцессов результаты отправляются в основной процесс, тем самым сокращая общее время построения.

Альтернатива

  • thread-loader(официальный запуск)
  • parallel-webpack
  • HappyPack
HappyPack

Примечание: так как автор HappyPack постепенно потерял интерес к js, в будущем обслуживание будет сокращено, рекомендуется использовать thread-loader для webpack4 и выше.

Принцип: каждый раз, когда webpack анализирует модуль, HappyPack назначает его и его зависимости рабочему процессу; HappyPack разделит модули на один.Например,модулей у нас несколько,и эти модули будут переданы в HappyPack.Сначала после метода запуска компилятора вебпака(хука) процесс дойдет до HappyPack,а HappyPack сделает некоторая инициализация.После инициализации он создаст пул потоков, пул потоков будет выделять модули в задаче сборки, например, модуль и некоторые его зависимости будут выделены одному из потоков HappyPack и так далее, затем пул потоков HappyPack будет включать в себя несколько потоков, в это время эти потоки пула потоков будут обрабатывать модули и их зависимости соответственно.После завершения обработки будет процесс связи, и обработанные ресурсы будут переданы в основной процесс HappyPack для завершения всей конструкции Процесс.

HappyPack

Скопируйте несколько одинаковых страниц из каталога src

src.png

Выполните упаковку перед внедрением HappyPackbuild.png

Установитьnpm install --save-dev happypackПримечание. Для использования webpack4 требуется версия HappyPack5.0. После вступления меняем компиляцию правил с js на happypack/loader

rules: [
      {
        test: /.js$/, //对所有js后缀的文件进行编译
        use: [
          // 'babel-loader'
          'happypack/loader',
        ],
      },
]

Добавить happypack-loader в плагин

  plugins: [
    new HappyPack({
      // 3) re-add the loaders you replaced above in #1:
      loaders: ['babel-loader'],
    }),
]

happypack.png

Очевидно, видно, что скорость упаковки намного выше после использования happypack.

thread-loader

Принцип: как и в HappyPack, каждый раз, когда веб-пакет анализирует модуль, загрузчик потока назначит его и его зависимости рабочему процессу; Установить

npm install --save-dev thread-loader

Добавьте загрузчик потоков в правило, загрузчик потоков может выполнять некоторую настройку, например рабочие (количество процессов)

rules: [
      {
        test: /.js$/, //对所有js后缀的文件进行编译
        include: path.resolve('src'), //表示在src目录下的.js文件都要进行一下使用的loader
        use: [
          'babel-loader',
          {
            loader: 'thread-loader',
            options: {
              workers: 3,
            },
          },
          // 'happypack/loader',
        ],
      },
]

thread-loader.png

После использования загрузчика потоков скорость упаковки также значительно повышается.

3. Многопроцессорное/многоэкземплярное сжатие кода (параллельное сжатие)

После того, как код построен, перед выводом выполняется этап сжатия кода, который также может быть сжат параллельно для достижения цели оптимизации скорости построения;

Альтернатива

  • webpack-parallel-uglify-plugin
  • uglifyjs-webpack-plugin
  • terser-webpack-plugin** (рекомендуется для webpack 4.0, поддерживает сжатый код es6)**
npm install terser-webpack-plugin --save-dev
const TerserPlugin = require('terser-webpack-plugin');

Добавить плагин TerserPlugin в оптимизацию, открыть параллельно

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        //代码压缩插件
        parallel: 4, //开启并行压缩
      }),
    ],
  },

4. Повысьте скорость упаковки за счет субподряда

можно использоватьhtml-webpack-externals-pluginОтделите базовый пакет и импортируйте необходимые файлы ресурсов в виде CDN после разделения. Недостатком является то, что базовая библиотека должна указывать CDN. В реальной разработке проекта могут быть ссылки на несколько базовых библиотек и некоторые бизнес-пакеты.

new HtmlWebpackExternalsPlugin({
  externals: [
    {
      module: 'react',
      entry: 'https://unpkg.com/react@16/umd/react.development.js',
      global: 'React',
    },
  ],
})

Дальнейший субподряд с использованием предварительно скомпилированных ресурсных модулей

Официальный встроенный подключаемый модуль DLLPlugin веб-пакета используется для подпакета, а DdllReferenceRlugin ссылается на manifest.json. DLLPlugin может упаковывать компоненты и библиотеки фреймворка, задействованные в проекте, такие как react, reactdom, redux и т.д., в файл, и одновременно генерироватьmanifest.jsonдокументmanifest.jsonЭто описание отдельного пакета. Фактический проект может ссылаться на manifest.json. После ссылки будет связан пакет, разделенный DLLPlugin. Этот файл используется для созданияDLLReferencePluginСопоставление со связанными зависимостями

  1. Сначала используйте DLLPlugin для субподряда

Создайте отдельный профиль сборки,webpack.dll.js, укажите пакеты, которые необходимо разделить в файле конфигурации Добавьте оператор компиляции dll в package.json

  "scripts": {
    "dll": "webpack --config webpack.dll.js"
  }

webpack.dll.js

const webpack = require('webpack');
const path = require('path');

module.exports = {
  mode: 'development',
  entry: {
    //对应output 中的library
    library: ['react', 'react-dom'],
  },
  output: {
    filename: '[name]_[chunkhash].dll.js', //分离出来的文件名称,一个占位符+hash.dll.js  [name]对应的是entry的library
    path: path.join(__dirname, 'build/library'), //输出到当前目录下的build目录
    library: '[name]', //打包后暴露出的库的名字
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]_[hash]', //打包后library.json中的name
      path: path.join(__dirname, 'build/library/[name].json'), //打包后生成[name].json的路径
    }),
  ],
};

npm run dllПосле этого в каталоге сборки будут сгенерированы два файла

image.png

То есть упомянутый ранее manifest.json

использовать после сборкиDllReferencePluginЦитироватьmanifest.json

plugins: [
    new webpack.DllReferencePlugin({
      manifest: require('./build/library/library.json'),
    }),
]

5. Увеличьте скорость вторичной упаковки за счет кэширования

  • babel-loader включает кеширование
  • terser-webpack-plugin включает кеширование
  • Используйте cache-loader или hard-source-webpack-plugin
    new HappyPack({
      loaders: ['babel-loader?cacheDirectory=true'],
    })

Установите cacheDirectory=true для babel-loader, чтобы включить кеширование

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        //代码压缩插件
        parallel: 4, //开启并行压缩
        cache: true,
      }),
    ],
  },

Установите кеш подключаемого модуля terser-webpack-plugin: true, чтобы включить кеширование

Используйте жесткий-исходный-webpack-плагин

npm install --save-dev hard-source-webpack-plugin
  plugins: [
    new HardSourceWebpackPlugin()  
]

Первый запуск начинает запись в файл кешаimage.png

image.png

После открытия кеша скорость упаковки значительно повышается

6. Минимизируйте цель сборки

Соберите как можно меньше модулей, например, babel-loader не разрешает node_modules

  • Оптимизация конфигурации resolve.modules (уменьшение иерархии поиска модулей)
  • Оптимизация конфигурации resolve.mainFields
  • Оптимизация конфигурации resolve.extensions

В-четвертых, оптимизация объема упаковки

В основном оптимизируйте объем ресурсов упакованных изображений, файлов js и css.

1. Сжатие изображений

Используя imagemin библиотеки Node, настройтеimage-webpack-loaderОптимизируйте изображение, когда плагин будет создан, он определит ресурс изображения и оптимизирует ресурс изображения.imageminАнализ преимуществ

  • imagemin имеет много вариантов настройки
  • Могут быть введены дополнительные сторонние плагины для оптимизации, такие какpngquant
  • Может импортировать различные форматы изображений

imageminпринцип сжатия

  • pngquant: это компрессор PNG, который значительно уменьшает размер файла за счет преобразования изображений в более эффективный 8-битный формат PNG с альфа-каналом (обычно на 60%-80% меньше, чем 24/32-битные файлы PNG);

Альфа-канал(Альфа-канал) относится к прозрачности и полупрозрачности изображения.

  • pngcrush: его основная цель — уменьшить размер потока данных PNG IDAT, пробуя различные уровни сжатия и методы фильтрации PNG;
  • optipng: его подход вдохновлен pngcrush. optipng повторно сжимает файлы изображений до меньшего размера без потери информации;
  • tingpng: он также преобразует 24-битные файлы PNG в меньшие 8-битные изображения с индексами, и все ненужные метаданные также будут удалены;
npm install image-webpack-loader --save-dev
rules: [
      {
        test: /.(png|jpg|gif|jpeg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name]_[hash:8].[ext]',
            },
          },
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65,
              },
              // optipng.enabled: false will disable optipng
              optipng: {
                enabled: false,
              },
              pngquant: {
                quality: [0.65, 0.9],
                speed: 4,
              },
              gifsicle: {
                interlaced: false,
              },
              // the webp option will enable WEBP
              webp: {
                quality: 75,
              },
            },
          },
        ],
      }
]

2. Сотрите бесполезный CSS

Вы можете просмотреть код через плагин, чтобы определить класс CSS, который был использован. Установить плагинnpm i purgecss-webpack-plugin -D

const PurgecssPlugin = require('purgecss-webpack-plugin');
const PATHS = {
  src: path.join(__dirname, 'src'),
};
plugins: [
new PurgecssPlugin({
      paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
    }),
]

3. Динамический полифилл

Что такое полифилл?

По умолчанию babel преобразует только новый синтаксис (синтаксис) JavaScript, такой как стрелочные функции и т. д., но не преобразует новые API, такие как Iterator, Generator, Set, Maps, Proxy, Reflect, Symbol, Promise и другие глобальные объекты. а также некоторые определенные в глобальных объектах методы выше (например, Object.assign) не будут перекодированы, поэтому нам нужен полифилл; Связь:у-у-у. Краткое описание.com/afraid/482285279…

официальное объяснение

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

пройти черезcaniuseЗапрос показывает, что обещания имеют совместимость 96,17%.image.png

Так как полифилл не обязателен, загружать полифилл нужно только некоторым браузерам, не поддерживающим новый синтаксис es6.Необязательно всем пользователям загружать полифилл для 3,5% пользователей;

мы можем пройтиpolyfill-service, вернуть пользователю только требуемый полифилл Каждый раз, когда пользователь открывает страницу, браузер будет запрашивать полифилл-сервис, а полифилл-сервис идентифицирует пользовательский агент пользователя и доставляет различные полифиллы. Как использовать динамический сервис Polyfill пройти черезpolyfill.ioОфициально предоставляемые услуги, самодельные сервисы полифиллаpoly fill.IO/V3/URL - не IL...

или путем введения cdn<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>загрузить polyfill-сервис может быть загруженполифилл.IO/V3/полифилл…URL-адрес для просмотра User Agent разных браузеров;

На этом мы заканчиваем содержание оптимизации скорости сборки пакета webpack4 и оптимизации объема.Эта статья основана на изученииЧенг ЛюфэнКраткое изложение практики преподавателя по курсу «Игра с веб-пакетом», добро пожаловать на обсуждение и исправление вышеизложенного.