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

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

Скриншот приложения

Мера

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

  • Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим полноэкранный .

Идите вперед и нажмите на своего любимого котенка! В этом приложении используется база данных Firebase Realtime , поэтому результаты обновляются в режиме реального времени и синхронизируются с данными всех остальных пользователей приложения. 🐈

  1. Нажмите «Control+Shift+J» (или «Command+Option+J» на Mac), чтобы открыть DevTools.
  2. Откройте вкладку «Сеть» .
  3. Установите флажок Отключить кеш .
  4. Перезагрузите приложение.

Исходный размер пакета: 992 КБ.

Для загрузки этого простого приложения поставляется JavaScript объемом почти 1 МБ!

Взгляните на предупреждения проекта в DevTools.

  • Нажмите на вкладку «Консоль» .
  • Убедитесь, что Warnings включены в раскрывающемся списке уровней рядом с входом Filter .

Фильтр предупреждений

  • Взгляните на отображаемое предупреждение.

Предупреждение консоли

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

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

Анализ пакета

В приложении есть две основные зависимости:

  • Firebase : платформа, предоставляющая ряд полезных сервисов для iOS, Android или веб-приложений. Здесь его база данных в реальном времени используется для хранения и синхронизации информации о каждом котенке в режиме реального времени.
  • Moment.js : служебная библиотека, упрощающая обработку дат в JavaScript. Дата рождения каждого котенка хранится в базе данных Firebase, а moment используется для расчета его возраста в неделях.

Как могут всего две зависимости привести к тому, что размер пакета составит почти 1 МБ? Ну, одна из причин заключается в том, что любая зависимость, в свою очередь, может иметь свои собственные зависимости, поэтому их намного больше, чем две, если учитывать каждую глубину/ветвь «дерева» зависимостей. Приложению легко относительно быстро стать большим, если в него включено много зависимостей.

Проанализируйте сборщик, чтобы лучше понять, что происходит. Существует ряд различных инструментов, созданных сообществом, которые могут помочь в этом, например webpack-bundle-analyzer .

Пакет для этого инструмента уже включен в приложение как devDependency .

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

Это означает, что его можно использовать непосредственно в файле конфигурации веб-пакета. Импортируйте его в самое начало webpack.config.js :

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

Теперь добавьте его как плагин в самый конец файла в массиве plugins :

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

Когда приложение перезагрузится, вы должны увидеть визуализацию всего пакета, а не самого приложения.

Анализатор пакетов веб-пакетов

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

Размер статистики Размер до любого уменьшения или сжатия.
Анализируемый размер Размер фактического пакета внутри бандла после его компиляции. Веб-пакет версии 4 (который используется в этом приложении) автоматически минимизирует скомпилированные файлы, поэтому он меньше размера статистики.
Размер в сжатом виде Размер пакета после его сжатия с помощью кодировки gzip. Этой теме посвящено отдельное руководство.

С помощью инструмента webpack-bundle-analyzer легче выявить неиспользуемые или ненужные пакеты, составляющие большую часть пакета.

Удаление неиспользуемых пакетов

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

  • firestore
  • auth
  • storage
  • messaging
  • functions

Все это замечательные сервисы, предоставляемые Firebase (более подробную информацию можно найти в документации ), но ни один из них не используется в приложении, поэтому нет смысла импортировать их все.

Отмените изменения в webpack.config.js , чтобы снова увидеть приложение:

  • Удалите BundleAnalyzerPlugin из списка плагинов:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • А теперь удалите неиспользуемый импорт из верхней части файла:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

Теперь приложение должно нормально загружаться. Измените src/index.js , чтобы обновить импорт Firebase.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

Теперь, когда приложение перезагружается, предупреждение DevTools не отображается. Открытие панели DevTools Network также показывает значительное уменьшение размера пакета:

Размер пакета уменьшен до 480 КБ.

Было удалено более половины размера пакета. Firebase предоставляет множество различных сервисов и дает разработчикам возможность включать только те, которые действительно необходимы. В этом приложении для хранения и синхронизации всех данных использовалась только firebase/database . Импорт firebase/app , который настраивает поверхность API для каждой из различных служб, требуется всегда.

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

Хотя размер пакета значительно уменьшился, предстоит еще много работы! 😈

Удаление ненужных пакетов

В отличие от Firebase, импортировать части библиотеки moment не так просто, но, может быть, ее можно полностью удалить?

День рождения каждого милого котёнка хранится в формате Unix (миллисекунды) в базе данных Firebase.

Даты рождения хранятся в формате Unix.

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

Как всегда, старайтесь не копировать и вставлять, следуя инструкциям здесь. Начните с удаления moment из импорта в src/index.js .

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

Существует прослушиватель событий Firebase, который обрабатывает изменения значений в нашей базе данных:

favoritesRef.on("value", (snapshot) => { ... })

Выше этого добавьте небольшую функцию для расчета количества недель от заданной даты:

const ageInWeeks = birthDate => {
  const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
  const diff = Math.abs((new Date).getTime() - birthDate);
  return Math.floor(diff / WEEK_IN_MILLISECONDS);
}

В этой функции вычисляется разница в миллисекундах между текущей датой и временем (new Date).getTime() и датой рождения ( birthDate , уже в миллисекундах) и делится на количество миллисекунд в одной неделе.

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

favoritesRef.on("value", (snapshot) => {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) => {
    const birthday = moment(birthDates[index]);

    return `
      <li>
        <img src=${kittiePic} onclick="favKittie(${index})">
        <div class="extra">
          <div class="details">
            <p class="name">${names[index]}</p>
            <p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
            <p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
          </div>
          <p class="score">${favorites[index]} ❤</p>
        </div>
      </li>
    `})
});

Теперь перезагрузите приложение и еще раз посмотрите на панель «Сеть» .

Размер пакета уменьшен до 225 КБ.

Размер нашего бандла снова уменьшился более чем вдвое!

Заключение

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

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

Когда дело доходит до удаления ненужных библиотек , все может быть немного сложнее. Важно тесно сотрудничать со своей командой и посмотреть, есть ли возможность упростить части кодовой базы. Может показаться, что удаление moment в этом приложении было бы правильным каждый раз, но что, если бы нужно было обрабатывать часовые пояса и разные локали? Или что, если бы были более сложные манипуляции с датами? Манипулирование и анализ даты/времени может оказаться очень сложным, и такие библиотеки, как moment и date-fns значительно упрощают это.

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