В этой лабораторной работе повысьте производительность следующего приложения, удалив все неиспользуемые и ненужные зависимости.
Мера
Всегда полезно сначала оценить эффективность работы веб-сайта, прежде чем приступать к его оптимизации.
- Для предварительного просмотра сайта нажмите «Просмотреть приложение» . Затем нажмите «Полный экран».
.
Нажмите на своего любимого котёнка! В этом приложении используется база данных Firebase Realtime , поэтому результаты обновляются в режиме реального времени и синхронизируются с данными каждого пользователя приложения. 🐈
- Нажмите `Control+Shift+J` (или `Command+Option+J` на Mac), чтобы открыть DevTools.
- Откройте вкладку Сеть .
- Установите флажок Отключить кэш .
- Перезагрузите приложение.
Для загрузки этого простого приложения отправляется JavaScript объемом почти 1 МБ!
Взгляните на предупреждения проекта в DevTools.
- Нажмите на вкладку «Консоль» .
- Убедитесь, что в раскрывающемся списке уровней рядом с полем
Filter
включенWarnings
.
- Взгляните на отображаемое предупреждение.
Firebase, одна из библиотек, используемых в этом приложении, проявляет милосердие, предупреждая разработчиков о необходимости импортировать не весь пакет, а только используемые компоненты. Другими словами, в этом приложении есть неиспользуемые библиотеки, которые можно удалить, чтобы ускорить загрузку.
Бывают также случаи, когда используется определённая библиотека, но может быть более простая альтернатива. Концепция удаления ненужных библиотек рассматривается далее в этом руководстве.
Анализируем связку
В приложении есть две основные зависимости:
- Firebase : платформа, предоставляющая ряд полезных сервисов для iOS, Android и веб-приложений. Здесь её база данных Realtime Database используется для хранения и синхронизации информации о каждом котёнке в режиме реального времени.
- Moment.js : вспомогательная библиотека, упрощающая работу с датами в JavaScript. Дата рождения каждого котёнка хранится в базе данных Firebase, а
moment
используется для расчёта его возраста в неделях.
Как всего две зависимости могут способствовать увеличению размера пакета почти до 1 МБ? Одна из причин заключается в том, что любая зависимость, в свою очередь, может иметь свои собственные зависимости, так что, если учесть каждую ветку/ветвь «дерева» зависимостей, их будет гораздо больше, чем две. Приложение может легко и относительно быстро стать большим, если в него включено много зависимостей.
Проанализируйте сборщик, чтобы лучше понять, что происходит. Существует ряд инструментов, разработанных сообществом, которые могут помочь в этом, например, webpack-bundle-analyzer
.
Пакет для этого инструмента уже включен в приложение как devDependency
.
"devDependencies": {
//...
"webpack-bundle-analyzer": "^2.13.1"
},
Это означает, что его можно использовать непосредственно в файле конфигурации Webpack. Импортируйте его в самое начало webpack.config.js
:
const path = require("path");
//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
Теперь добавьте его как плагин в самый конец файла в массиве plugins
:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
После перезагрузки приложения вы увидите визуализацию всего пакета, а не само приложение.
Не такие милые, как котята 🐱, но всё равно невероятно полезные. При наведении курсора на любой из пакетов отображается его размер в трёх разных вариантах:
Размер статистики | Размер до какой-либо минимизации или сжатия. |
---|---|
Разобранный размер | Размер фактического пакета в бандле после компиляции. Версия 4 Webpack (используемая в этом приложении) автоматически минимизирует скомпилированные файлы, поэтому он меньше, чем указанный в статистике. |
Размер в сжатом виде | Размер пакета после сжатия с помощью 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 также показывает значительное уменьшение размера пакета:
Размер пакета был уменьшен более чем на половину. Firebase предоставляет множество различных сервисов и даёт разработчикам возможность включать только те, которые действительно необходимы. В этом приложении для хранения и синхронизации всех данных использовался только firebase/database
. Импорт firebase/app
, который настраивает API-интерфейс для каждого из сервисов, обязателен всегда.
Многие другие популярные библиотеки, такие как lodash
, также позволяют разработчикам выборочно импортировать различные части своих пакетов. Обновление импорта библиотек в приложении с целью включения только используемых компонентов может значительно повысить производительность, не прилагая особых усилий.
Хотя размер пакета значительно уменьшился, работы ещё много! 😈
Удаление ненужных пакетов
В отличие от Firebase, импорт частей библиотеки moment
не так прост, но, может быть, ее можно полностью удалить?
День рождения каждого милого котенка хранится в формате Unix (миллисекунды) в базе данных Firebase.
Это временная метка конкретной даты и времени, представленная количеством миллисекунд, прошедших с 00:00 UTC 1 января 1970 года. Если текущую дату и время можно вычислить в том же формате, вероятно, можно построить небольшую функцию для определения возраста каждого котёнка в неделях.
Как всегда, постарайтесь не копировать и не вставлять код. Начните с удаления 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> `}) });
Теперь перезагрузите приложение и еще раз взгляните на панель «Сеть» .
Размер нашего пакета снова уменьшился более чем в полтора раза!
Заключение
С помощью этой лабораторной работы вы должны получить хорошее представление о том, как анализировать конкретный пакет и почему удаление неиспользуемых или ненужных пакетов может быть так полезно. Прежде чем приступить к оптимизации приложения с помощью этого метода, важно знать, что в более крупных приложениях это может быть значительно сложнее .
Что касается удаления неиспользуемых библиотек , попробуйте выяснить, какие части пакета используются, а какие нет. Если пакет выглядит подозрительно и, похоже, нигде не используется, сделайте шаг назад и проверьте, каким зависимостям верхнего уровня он может понадобиться. Попробуйте найти способ по возможности отделить их друг от друга.
Когда дело доходит до удаления ненужных библиотек , всё может быть немного сложнее. Важно тесно сотрудничать с вашей командой и понять, есть ли возможность упростить некоторые части кодовой базы. Удаление moment
из этого приложения может показаться правильным решением, но что, если необходимо учитывать часовые пояса и различные локали? Или если требуются более сложные операции с датами? Работа с датами и временем может быть очень сложной, и такие библиотеки, как moment
и date-fns
значительно упрощают этот процесс.
Все является компромиссом, и важно оценить, стоит ли вообще тратить усилия и сложность на развертывание индивидуального решения вместо использования сторонней библиотеки.