[оптимизация производительности webpack] скорость компиляции с 50S до 7S

Webpack
[оптимизация производительности webpack] скорость компиляции с 50S до 7S

В этой статье в основном записаны следующиеwebpackОптимизация производительности

статус-кво

По мере того, как проект продолжает расти и развиваться, количество компонентов начинает становиться все больше и больше, и проект начинает становиться большим,webpackВремя компиляции будет все больше и больше, наш текущий проект компилируется один раз в40s ——70sМежду тем, это очень неэффективная операция. Есть много способов оптимизации, в проекте уже сделано многое, в этой статье мы оптимизируем и объясним с точки зрения кэширования.

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

  • babel-loaderизcacheDirectory
  • cache-loader
  • dllдинамически подключаемая библиотека
  • HardSourceWebpackPlugin

Сначала о выводе: первый уже в проекте, второй и третий малоэффективны, а четвертый добился ожидаемого эффекта.

Наша версия веб-пакета: 4.41.2, система: mac os

Анализ узких мест

Первым шагом в оптимизации должен быть анализ текущей производительности, здесь мы используемspeed-measure-webpack-pluginДелайте анализ скорости

// 安装
npm install --save-dev speed-measure-webpack-plugin
// 使用方式
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
 
const smp = new SpeedMeasurePlugin();
 
const webpackConfig = smp.wrap({
  plugins: [
    new MyPlugin(),
    new MyOtherPlugin()
  ]
});

Результаты аналогичны следующим, вы можете видеть, что каждыйLoaderтак же какPluginотнимает много времени, с этим мы можем «прописать правильное лекарство»

Но следует отметить, что:HardSourceWebpackPlugin и speed-measure-webpack-plugin нельзя использовать вместе, меня это надолго угнетало

cacheDirectory из babel-loader

babel-loaderс разрешенияBabelа такжеwebpackпереводитьJavaScriptфайл, иногда, если мы запускаемbabel-loaderМедленно, вы можете рассмотреть возможность обеспечения того, чтобы документы были нанесены возможными. Вы можете использовать/\.m?js$/совпадать, чтобы можно было перевестиnode_modulesкаталог или другой нежелательный исходный код, вызывающий снижение производительности

в состоянии пройтиexcludeИсключите некоторые файлы, которые не нужно компилировать. Например, следующее не будет экранированоnode_modulesа такжеbower_componentsСодержимое под папкой

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-proposal-object-rest-spread']
        }
      }
    }
  ]
}

Вы также можете сделать это, используяcacheDirectoryвариант, будетbabel-loaderУскорьтесь хотя бы в два раза. Это кэширует результат перевода в файловую систему.cacheDirectoryПо умолчаниюfalse. Если установлено, указанный каталог будет использоваться для кэшированияloaderрезультат исполнения. ПослеwebpackСборка попытается прочитать кеш, чтобы избежать высокого потребления производительности, которое может происходить каждый раз при ее выполнении.BabelПроцесс перекомпиляции (recompilation process). Если установлено нулевое значение(loader: 'babel-loader?cacheDirectory') илиtrue (loader: 'babel-loader?cacheDirectory=true'), загрузчик будет использовать каталог кеша по умолчаниюnode_modules/.cache/babel-loader, если не найден ни в одном корневом каталогеnode_modulesкаталог, он будет переведен обратно в каталог временных файлов операционной системы по умолчанию.

{
  test: /\.js$/,
  use: 'babel-loader?cacheDirectory',
  include: [resolve('src'), resolve('test') ,resolve('node_modules/webpack-dev-server/client')]
}

cache-loader

Кромеbabel-loader, если мы хотим другиеloaderРезультаты обработки тоже кешируются, что делать?

Ответ заключается в том, что вы можете использоватьcache-loader. В некоторых накладных расходахloaderдобавлено доcache-loader, чтобы кэшировать результаты на диск

Установить

npm install --save-dev cache-loader

настроить

module.exports = {
  module: {
    rules: [
      {
        test: /\.ext$/,
        use: ['cache-loader', ...loaders],
        include: path.resolve('src'),
      },
    ],
  },
};

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

В дополнение к конфигурации по умолчанию,cache-loaderДоступны еще несколько вариантов, см.cache-loader

схема кеширования dll

Что такое DLL?

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

Зачем использовать DLL?

Причина в том, что динамическую библиотеку, содержащую большое количество повторно используемых модулей, нужно скомпилировать только один раз, и модули, включенные в динамическую библиотеку, не будут перекомпилироваться в последующем процессе построения, но код в динамической библиотеке будет использоваться напрямую. Поскольку большинство библиотек динамической компоновки содержат часто используемые сторонние модули, такие какVue react、react-dom, пока версия этих модулей не обновлена, динамическую библиотеку не нужно перекомпилировать

как использовать?

Чтобы выполнить следующие три шага:

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

использовался раньшеDllPluginа также DllReferencePluginГотово, но его конфигурация очень сложная и dll нужно перегенерировать вручную, если файлы обновляются. выбрано здесьAutoDllPlugin, он автоматически выполнит функции двух вышеуказанных плагинов, т.е.Vue-cliплагин, который я использовал

Установить:

webpack 4

npm install --save-dev autodll-webpack-plugin

webpack 2 / 3

npm install --save-dev autodll-webpack-plugin@0.3

Основное использование:

plugins: [
  new HtmlWebpackPlugin({
    inject: true,
    template: './src/index.html',
  }),
  new AutoDllPlugin({
    inject: true, // will inject the DLL bundles to index.html
    filename: '[name].js',
    entry: {
      vendor: [
        'react',
        'react-dom'
      ]
    }
  })
]

До оптимизации

Оптимизировано

Первая компиляция:

Вторая компиляция:

Оптимизировано на несколько секунд, с небольшим эффектом

Это не сработало так хорошо, потому чтоwebpack4Спектакль достаточно отличный.Vue-cliтакже убрал эту функцию

HardSourceWebpackPlugin

Установить:

npm install --save-dev hard-source-webpack-plugin
# or
yarn add --dev hard-source-webpack-plugin

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

// webpack.config.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

module.exports = {
  context: // ...
  entry: // ...
  output: // ...
  plugins: [
    new HardSourceWebpackPlugin()
  ]
}

До оптимизации

Как видите, требуется 50 с.

Оптимизировано

первый старт

второй старт

Требуется всего 7 с, что снижает43 s, скорость увеличивается примерно на 80%. Цель оптимизации достигнута!

Скорость горячего обновления

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

До оптимизации

js: 2443ms 1634ms 1844ms 2532ms 1443ms 1248ms

html: 1094ms 1232ms 1119ms 1490ms 1264ms

css: 1422ms 1186ms 1341ms 1562ms 1183ms

Оптимизировано

js: 2429ms 2436ms 2860ms 2528ms 1917ms 1487ms 1450ms 1450ms 1557ms 2198ms

html: 2855ms 1569ms 1400ms 1298ms 1204ms 1299ms 1578ms 1485ms 2028ms

css: 2035ms 1406ms 1415ms 1600ms 1773ms 1604ms

Для сравнения, это иногда медленнее, но в целом приемлемо. Но это также имело некоторое влияние, поэтому проект поднял дваnpm scriptкоманду, если вы не хотите ее открывать, вы можете напрямуюnpm run dev:noCache

"scripts": {
  "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --cache=true",
  "dev:noCache": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --cache=false"
}

существуетbuild/webpack.dev.conf.jsсередина

if (args.cache) {
  devConfig = merge(devConfig, {
    plugins: [new HardSourceWebpackPlugin()]
  })
}

еще раз подчеркнуть:

HardSourceWebpackPlugin и speed-measure-webpack-plugin нельзя использовать вместе

Глядя в будущее

webpack 5Вышел, с привлекательной фичей - постоянным кэшированием (говорят, что идея связана сHardSourceWebpackPluginсогласуется)

пройти черезcacheКэшwebpackмодули и chunk, чтобы улучшить скорость сборки.cacheбудет установлен в режиме разработки наtype: 'memory'и отключен в производственном режиме

module.exports = {
  cache: {
    // 1. 将缓存类型设置为文件系统
    type: 'filesystem',

    buildDependencies: {
      // 2. 将你的 config 添加为 buildDependency,以便在改变 config 时获得缓存无效
      config: [__filename],

      // 3. 如果你有其他的东西被构建依赖,你可以在这里添加它们
      // 注意,webpack、加载器和所有从你的配置中引用的模块都会被自动添加
    },
  },
};

Суммировать

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

Выше, я надеюсь помочь вам

Ссылаться на