Секрет сохранения скорости Webpack: практическое руководство по повышению производительности сборки

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

Советы по поддержанию скорости Webpack: практическое руководство по повышению производительности сборки

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

Строительный инструмент прошлых лет: ткацкий станок, соединенный с жаккардом.

предисловие

2017 год был амбициозным для фронтенд-команды Slack. После нескольких лет быстрой итеративной разработки у нас много технического долга и большие планы на масштабную модернизацию. Во-первых, мы планируем переписать наши компоненты пользовательского интерфейса на React и везде использовать современный синтаксис JavaScript. Однако, прежде чем мы сможем надеяться, что это может произойти, нам нужна система сборки для поддержки этой новой туманности инструментов.

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

Переход на webpack для нашего проекта прошел в основном гладко. Это было гладко, пока не столкнулись с проблемами производительности сборки. Наши сборки заняли минуты, а не секунды: это далеко от соединений второго уровня, к которым мы привыкли. Веб-команда Slack может развертывать 100 раз в любой будний день, поэтому мы ощутили резкое увеличение времени сборки.

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

Прежде чем начать, измерьте

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

Инспекторы для Node.js

Node поставляется со встроенным инструментом, который можно использовать для анализа сборок.inspector. Если вы не знакомы с профилированием, не волнуйтесь: Google делает все возможное, чтобы объяснитьДетали реализации. Приблизительное понимание фазы сборки WebPack будет очень полезным, хотяих документацияКратко освещает это, но прочтите некоторыеосновной кодочень полезно.

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

долгосрочная запись

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

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

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

Недорогие плагины для измерения

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

UglifyJSPluginявляется типичным подключаемым модулем измерения, этот метод работает, потому что большая часть его работы выполняется вoptimize-chunk-assetsсцена. Вот простая процедура плагина:

let CrudeTimingPlugin = function() {};

CrudeTimingPlugin.prototype.apply = function(compiler) {
  compiler.plugin('compilation', (compilation) => {
    let startOptimizePhase;

    compilation.plugin('optimize-chunk-assets', (chunks, callback) => {
      // 使用粗略测量压缩时间的方法。
      // UglifyJSPlugin 在这个编译阶段完成全部工作,
      // 所以我们计算整个阶段的时间。
      startOptimizePhase = Date.now();

      // 对于异步阶段,不要忘记调用回调函数
      callback();
    });

    compilation.plugin('after-optimize-chunk-assets', () => {
      const optimizePhaseDuration = Date.now() - startOptimizePhase;
        console.log(`optimize-chunk-asset phase duration: ${optimizePhaseDuration}`);
      });
    });
};

module.exports = CrudeTimingPlugin;

Цель приведенного выше примера — грубо измерить разницу во времени выполнения UglifyJSPlugin. Будьте внимательны, чтобы понять, на каких этапах будет выполняться плагин, так как они могут перекрываться.

Добавьте его в список плагинов перед UglifyJS, например:

const CrudeTimingPlugin = require('./crude-timing-plugin');

module.exports = {
plugins: [
    new CrudeTimingPlugin(),
    new UglifyJSPlugin(),
  ]
};

Ценность этой информации намного превышает стоимость ее получения, и как только вы поймете, на что тратится ваше время, вы сможете эффективно сократить его.

Параллельная работа

Большая часть работы webpack по своей сути параллельна. Получите огромные результаты, распределяя работу между как можно большим количеством процессоров, и если у вас есть лишние ядра ЦП, которые нужно «сжечь», пришло время «сжечь».

К счастью, для этой цели создано множество пакетов:

  • parallel-webpackВся сборка веб-пакета будет выполняться параллельно. Мы используем его в Slack для создания соответствующих ресурсов для наших пяти языков программирования.
  • happypackбудет выполнять загрузчики параллельно, напримерthread-loaderНапример, написано и поддерживается основной командой webpack. И может работать в паре с babel-loader и другими транспайлерами.
  • Пользователи плагина UglifyJS могут использовать недавно добавленныйПараллельный вариант

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

уменьшить нагрузку

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

Упрощенное сжатие

Сжатие — это огромная трата времени — от одной трети до половины нашего времени сборки. Мы оценили различные инструменты, начиная отButternutприбытьbabel-minify, только чтобы обнаружить, что UglifyJS является самым быстрым в параллельной конфигурации.

Однако для нас основная информация о проблемах с производительностью, которые необходимо решитьпогребен под тирадой автора

Вопреки распространенному мнению, для большинства JavaScript удаление пробелов и изменение символов может сжать 95% кода и лежит в основе основного сжатия кода, а не сложного перекодирования. Можно просто отключить сжатие, чтобы ускорить сборку Uglify в 3-4 раза.

Мы попробовали, и результаты были ошеломляющими. Как и было обещано, скорость сжатия в 3 раза выше, а размер наших результирующих связанных файлов практически не вырос. Пользователи React, отключающие сжатие таким образом, должны быть осторожны с одним предостережением:detection methodsодеялоreact-devtoolsИспользуется для сообщения о том, что вы используете разрабатываемую версию React. После некоторых проб и ошибок мы обнаружили, что следующая конфигурация решила проблему:

new UglifyJsPlugin({
  uglifyOptions: {
    compress: {
      arrows: false,
      booleans: false,
      cascade: false,
      collapse_vars: false,
      comparisons: false,
      computed_props: false,
      hoist_funs: false,
      hoist_props: false,
      hoist_vars: false,
      if_return: false,
      inline: false,
      join_vars: false,
      keep_infinity: true,
      loops: false,
      negate_iife: false,
      properties: false,
      reduce_funcs: false,
      reduce_vars: false,
      sequences: false,
      side_effects: false,
      switches: false,
      top_retain: false,
      toplevel: false,
      typeofs: false,
      unused: false,

      // 除非声明了正在使用生产版本的react-devtools,
      // 否则关闭所有类型的压缩。
      conditionals: true,
      dead_code: true,
      evaluate: true,
    },
    mangle: true,
  },
}),

Примечание. Эта конфигурация предназначена для версии 1.1.2 подключаемого модуля веб-пакета UglifyJS.

Переменные обнаружения зависят от версии, пользователи React 16 могут использовать только _compress: false_.

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

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

При разработке очень часто приходится находить и вводить несколько пакетов с одним и тем же кодом. Когда это произойдет, работа компрессора излишне увеличится. мы упаковываем его черезwebpack Bundle Analyzerа такжеBundle BuddyДва микроскопа находят дубликаты и используют веб-пакеты.CommonsChunkPluginв общие блоки.

пропустить частичный разбор

Пока webpack ищет зависимости, он разрешает каждый файл JavaScript каксинтаксическое дерево. Этот процесс является дорогостоящим, поэтому, если вы уверены, что файл (или группа файлов) никогда не будет использовать операторы импорта, требования или определения, вы можете указать веб-пакету исключить их из процесса. Таким образом, пропуск больших библиотек может значительно повысить эффективность. Подробнее см.noParseопции.

исключать

Аналогичным образом можноисключатьдокументации, многие плагины предоставляютпохожие варианты. На самом деле это может повысить производительность таких инструментов, как трансляторы и компрессоры, которые также полагаются на синтаксическое дерево в своей работе. В Slack мы компилируем только тот код, который, как мы подтверждаем, использует функции ES6, и игнорируем минимизацию кода, который не доступен клиентам напрямую.

DLL-плагин

DllPluginПозволит вам удалить предварительно созданные пакеты для использования веб-пакетом на более позднем этапе, что идеально подходит для больших, менее движущихся зависимостей, таких как библиотека Vendor. Хотя это традиционно плагин, который требует много настроек,autodll-webpack-pluginПроложил путь для более простых реализаций и заслуживает внимания.

Используйте записи для стабилизации идентификаторов модулей

webpack присваивает идентификатор каждому модулю в дереве зависимостей. По мере добавления новых модулей и удаления других модулей дерево изменяется, изменяя идентификатор каждого модуля в нем. Эти идентификаторы помещаются в каждый файл, который создает веб-пакет, и смешение модулей высокого уровня может привести к ненужным пересборкам. используяrecordsЧтобы предотвратить это, стабилизируйте идентификатор модуля между сборками.

Создайте блок манифеста

В Slack мы кешируем кряки, используя хешированные имена файлов каждый раз, когда выпускается новая версия. Откройте вкладку «Сеть» инструментов разработчика вашего браузера, и вы увидите запрос на файл «_application.d4920286de51402132dc.min.js». Этот метод отлично подходит для управления кешем, но он также означает, что веб-пакет не может сопоставлять модули с соответствующими именами файлов, не прибегая к дайджестам.

Дайджест — это простое сопоставление идентификаторов модулей с хэшами, когдаАсинхронный импорт модулей, webpack будет использовать это для разрешения имен файлов:

{
    0: "d4920286de51402132dc", /* ← 为应用打包而生成的哈希值 */
    1: "29a3cf9344f1503c9f8f",
    2: "e22b11ab6e327c7da035",
    /* .. 等等等 ... */
}

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

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

Source maps

Исходные карты являются ключевым инструментом для отладки, но их создание займет некоторое время, изменение веб-пакетовПараметры меню инструментов разработчикаИ выберите наиболее подходящий вам стиль отладки.cheap-source-mapРешение обеспечивает хороший баланс между производительностью сборки и возможностью отладки.

тайник

Наши развертывания происходят быстро, а это означает, что часто между текущей сборкой и предыдущей есть лишь небольшие различия. С кэшированием в нужном месте мы можем ускорить большую часть работы, которую в противном случае выполнял бы webpack.

Мы используемcache-loaderкэшировать результаты (пользователи babel-loader обычно предпочитают использовать егоВстроенный кеш, UglifyJSPpluginВстроенный кеш, и добавилHardSourceWebpackPlugin.

Небольшая заметка о HardSourceWebpackPlugin

Большая часть работы веб-пакета выполняется вне загрузчика/плагина, и большая часть работы следует традиционному уклонению от кэширования. Для решения этой проблемы мы ввели плагинHardSourceWebpackPlugin, используемый для кэширования промежуточных результатов внутренней обработки модуля webpack.

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

И последнее замечание: не забывайте очищать кеш всякий раз, когда изменяется зависимость пакета — вы можете использоватьnpm postinstall scriptАвтоматически. Устаревший, несовместимый кеш может нанести ущерб вашим сборкам новыми и интересными способами.

держать версию в актуальном состоянии

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

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

Не забывайте обновлять свой пакет Node  — , это не единственный способ его улучшить.

инвестиции в оборудование

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

Когда наша миссия только начиналась, наш сервер сборки был членом семейства Amazon EC2, C3. Обновив типы экземпляров до продуктов C4 (более быстрые и мощные процессоры), мы увидели значительное улучшение времени сборки и параметров, связанных с параллелизмом, доступных для масштабирования по мере роста кодовой базы. Переход от компьютеров с поддержкой экземпляров к EBS, о котором обычно беспокоятся пользователи, не должен отчаиваться: webpack агрессивно кэширует файловые операции, и мы не заметили снижения производительности после перехода на EBS.

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

способствовать

Инфраструктурные проекты, такие как webpack, почти на удивление бедны; вклад в инструмент, который вы используете, улучшит экосистему этого инструмента для вас и других в сообществе, как во времени, так и в деньгах. Slack недавно сделал пожертвование проекту webpack, чтобы команда могла продолжать работу, и мы призываем других сделать то же самое.

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

позже

webpack — фантастический, универсальный инструмент, который не стоит целое состояние. Эти методы помогли нам сократить среднее время сборки со 170 до 17 секунд, и хотя они улучшили процесс развертывания для наших инженеров, они не были хорошо зарекомендовавшим себя проектом. Если у вас есть какие-либо идеи о том, как еще больше повысить производительность сборки, мы будем рады услышать от вас. Конечно, если вам нравится решать эти проблемыПриходите и работайте с нами!

Большое спасибо Mark Christian, Mioi Hanaoka, Anuj Nair, Michael «Z» Goddard, Sean Larkin и, конечно же, Tobias Koppers за их вклад в этот пост и проект webpack.

Расширенное чтение

благодарныйMatt Haugheyслужба поддержки.


Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.