JavaScript

Оптимизация размера сборки webpack

Spread the love

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

Наткнулся на testmysite от Google, проверил веб-страницу и получил следующие результаты:

Сайт был оценен как очень отзывчивый в плане дизайна, но буквально очень «медленный» по времени загрузки. Я изучил различные части кода для определения времени загрузки страницы, и этот пост служит руководством для тех, кто хочет оптимизировать то же самое.

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

$ webpack -p --progress
Hash: dbce3735c9520e2dc682
Version: webpack 1.14.0
Time: 54264ms
            Asset     Size  Chunks             Chunk Names
    dist/index.js  3.29 MB       0  [emitted]  main
dist/index.js.map  13.7 MB       0  [emitted]  main
   [0] multi main 40 bytes {0} [built]
    + 1374 hidden modules

У меня текущий размер пакета составил более 3 мегабайт, и это объясняет ужасные оценки с инструмента профилирования.

1. Проанализируйте зависимости вашего пакета

Я использовал webpack-bundle-analyzer, который анализирует статистику webpack и дает отличную визуализацию, чтобы просмотреть сравнение размеров зависимостей!

Установите пакет с помощью следующей команды

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

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

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// ...
plugins: [new BundleAnalyzerPlugin()]
// ...

Теперь при запуске сервера должна отображаться визуализация по адресу http://localhost:8888. Вы должны увидеть что-то похожее ниже, и вы можете перейти на любой уровень, чтобы узнать, какие пакеты нужно обрезать или удалить.

Это должно помочь найти тяжелые зависимости. Также при импорте зависимостей лучше импортировать только необходимые функции/компоненты из библиотек как показано ниже.

//1. Импорт всей библиотеку lodash
import lodash from 'lodash'
lodash.groupBy(rows, 'id')

//2. Импорт только необходимой функции
import groupBy from 'lodash/groupBy'
groupBy(rows, 'id')

2. Правильная среда в сборке

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

plugins: [...
    new webpack.DefinePlugin({
             'process.env.NODE_ENV': '"production"'
    }),
..]

3. Включить минимизированный source map

Когда вы создаете сборку для продакт, наряду с минимизацией и объединением ваших JavaScript файлов, вы генерируете исходную карту (source map), которая содержит информацию о ваших исходных файлах. Исходная карта с максимальным уровнем детализации может быть сгенерирована для среды разработки или подготовки. Но мы можем выбрать наиболее оптимизированную форму исходных карт для среды продакт.

Проверьте конфигурацию вашего webpack, часто можно увидеть devtool: ‘eval’, который является одним из самых быстрых способов создания приложений, в которых большая часть информации о коде разработки включена в вывод. Давайте переключим этот параметр на eval-source-map или cheap-module-source-map. Обратитесь к этой документации, чтобы узнать больше о каждом из этих параметров конфигурации.

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

$ webpack -p --progress
Hash: 68a52fddbcc2898a5899
Version: webpack 1.14.0
Time: 29757ms
            Asset     Size  Chunks             Chunk Names
    dist/index.js  1.71 MB       0  [emitted]  main
dist/index.js.map  464 bytes       0  [emitted]  main
   [0] multi main 40 bytes {0} [built]
    + 1365 hidden modules

С 3.29 МБ мы уменьшили до 1.71 МБ, а также стоит отметить, что уменьшился размер source map!

4. Другие известные плагины для оптимизации размера сборки

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

  • compression-webpack-plugin: плагин для сжатия ресурсов, который будет генерировать файлы .gz вместе с assets, и в зависимости от клиента сервера ресурсов может быть использован по мере необходимости.
  • dedupe-plugin: ищет одинаковые или похожие файлы и дедуплицирует их в выходных данных. Это связано с некоторыми накладными расходами, но может эффективно уменьшить размер файла. (доступно по умолчанию в Webpack v.2)
  • uglifyjs-plugin: минимизирует весь код JavaScript. Обратитесь к документации по множеству опций
  • ignore-plugin: удобен, когда вам нужно импортировать отдельные модули из библиотеки. Например, при использовании moment.js необязательно включать все локали, которые поставляются с библиотекой, а только те, которые необходимы. Это также показано в примере кода ниже.

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

...
var CompressionPlugin = require("compression-webpack-plugin");
...
let config = {
  entry: path.join(__dirname, '../app/index'),
  cache: false,
  devtool: 'cheap-module-source-map',
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      mangle: true,
      compress: {
        warnings: false, // Suppress uglification warnings
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        screw_ie8: true
      },
      output: {
        comments: false,
      },
      exclude: [/\.min\.js$/gi] // skip pre-minified libs
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
    new webpack.NoErrorsPlugin(),
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    })
    ...
  ],

Давайте еще раз проверим размер пакета с окончательной конфигурацией …

$ webpack -p --progress
Hash: 68a52fddbcc2898a5899
Version: webpack 1.14.0
Time: 29757ms
            Asset     Size  Chunks             Chunk Names
    dist/index.js  1.54 MB       0  [emitted]  main
dist/index.js.gz   390 KB        0  [emitted]  main
dist/index.js.map  464 bytes     0  [emitted]  main   
   [0] multi main 40 bytes {0} [built]
    + 1365 hidden modules

Обратите внимание на размер сжатого js-файла, он уменьшился до 390 КБ. Это должно значительно сократить время загрузки страницы. Давайте еще раз запустим тест гугл-профилировщика и проверим, как теперь работает сайт с последним пакетом сборки.

5. Разделение кода (Code Splitting)

Так же я хотел бы в этой статье упомянуть code splitting , как важный шаг к оптимизированной сборке webpack. Идея довольно проста. Если вы используете что-то вроде react-router для определения нескольких страниц в вашем приложении, легко создать дерево зависимостей с компонентами, определенными в маршруте в качестве отправной точки, и связать все ресурсы (js, css, images), необходимые для этого. Если вы используете динамический импорт в своем коде, webpack сможет разумно разделить фрагменты кода, требуемые для каждой страницей.

Более подробное описание code splitting для React вы сможете найти по этой ссылки, а для Vue найдете здесь.

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

Если вам понравился этот пост, пожалуйста, следуйте за мной в twitter для получения дополнительных обновлений на подобные темы ..
Оригинальная статья: Optimising your application bundle size with webpack

Была ли вам полезна эта статья?
[5 / 5]

Spread the love
Editorial Team

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

10 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

10 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago