3 стратегии радикального повышения производительности вашего веб-приложения
«В июле 2018 года Google снизит рейтинг медленных веб-сайтов для мобильного поиска» - Google Webmaster
Обзор
Понять производительность веб-приложений непросто. Существует огромное количество факторов, которые могут замедлить работу вашей системы: частота запросов, размер полезной нагрузки, протоколы кэширования, географические задержки в сети… Вы понимаете. Скорее всего, если вы читаете это, вы, вероятно, находитесь в том же положении, что и мы - думали о том, как эффективно обслуживать веб-приложение без ущерба для пользовательского опыта. В этом сообщении блога мы проанализируем, как мы продвинули наше веб-приложение до первоклассного сайта выше среднего, просто уменьшив нашу полезную нагрузку и размер пакета.
Я фронтенд-инженер в Agolo и работаю над различными проектами, чтобы довести Agolo до стандартов первоклассного прогрессивного веб-приложения. Производительность играет большую роль в продвижении к этому новому уровню качества, и с учетом того, что Google уделяет этому больше внимания, разработчики вынуждены либо адаптироваться, либо оставаться в стороне (драматическая музыка).
Веб-приложение Agolo работает как одностраничное приложение (SPA), созданное с помощью Meteor 1.6.1 и React. Первоначально SPA обслуживал огромный размер пакета, и, в свою очередь, сильно пострадал опыт пользователей с медленным подключением. Скорость загрузки страницы составляла около 35 секунд в медленном 3G, а оценка производительности была ниже 10 в аудитах маяка Chrome.
Это 3 стратегии, используемые в Agolo, которые привели к увеличению скорости загрузки страницы в 10 раз (теперь 3,6 с) и 6-кратного повышения оценки производительности (теперь 61).
- Сжатие Gzip - (снижение скорости загрузки медленной страницы 3G на 20 секунд)
- Конкретный импорт библиотеки - (уменьшение размера пакета на 1 МБ)
- Динамический импорт (разделение кода) - (уменьшение размера пакета на 1,2 МБ)
Gzip
Обслуживание несжатого пакета крайне неэффективно. Файлы со сжатием могут уменьшаться в размере до 90% и приводить к значительному повышению производительности. Gzip - это популярный алгоритм сжатия и формат в сети, и мы используем его здесь, в Agolo, для сжатия наших полезных данных. Gzip требует поддержки браузера, но вам не о чем беспокоиться, потому что большинство популярных браузеров поддерживают его (полный список здесь).
Хотя инструкции по включению Gzip различаются для разных веб-серверов, они по-прежнему очень похожи. Agolo использует Nginx в качестве прокси-сервера для нашего веб-приложения, и мы будем использовать его в следующих примерах, чтобы продемонстрировать, как настроить Gzip.
Вот как Gzip работает с Nginx:
- Клиент (браузер) отправит HTTP-запрос с
vary: Accept-Encoding
в его заголовке. Это означает, что браузер поддерживает сжатие. - Nginx получает запрошенную полезную нагрузку с веб-сервера.
- Nginx проверяет полезную нагрузку и выбирает, сжимать ее с помощью Gzip или нет.
- Nginx отвечает либо сжатыми, либо необработанными данными. Сжатые данные будут разархивированы браузером и обозначены HTTP-заголовком
Content-Encoding: gzip
Но как Nginx выбирает, какой запрос следует архивировать? Nginx делает это через свой файл конфигурации, и мы добавим сюда наши настройки Gzip. Для начала скопируйте эти строки кода в файл конфигурации Nginx.
Конфигурации Nginx работают по иерархии директив. Вот почему настройки Gzip должны быть помещены только в директиву server
, а директива location
унаследует их.
Указание gzip_types
(строка 9) перезаписывает настройки по умолчанию, поэтому важно явно объявить переопределенные типы MIME. Обратите внимание, что снова объявлено одно из значений по умолчанию, application/x-javascript
.
Перезапустите веб-приложение и проверьте вкладку сеть в Chrome. Вы должны увидеть, что некоторые Content-Encoding имеют формат gzip.
Конкретный импорт библиотеки
import { Snackbar, RaisedButton } from ‘material-ui’;
Импорт дженериков стоит дорого. Они заставляют Meteor объединять всю импортированную библиотеку, когда то, что вы можете использовать, является лишь ее небольшой частью. Раньше это приводило к значительному дублированию размера пакета веб-приложений Agolo.
Определяя весь импорт, мы смогли сократить импорт огромных библиотек. Однако даже один общий импорт заставит Meteor объединить всю библиотеку. Вы должны тщательно провести рефакторинг и убедиться, что указаны все экземпляры импорта. Ниже приведен пример конкретного импорта.
import Snackbar from ‘material-ui/Snackbar’; import RaisedButton from ‘material-ui/RaisedButton’;
С Meteor 1.5 у нас есть возможность визуализировать, что составляет весь наш пакет. Визуализатор пакетов - удобный инструмент для определения того, где лучше всего уменьшить размер пакета, указав импорт. Чтобы открыть визуализатор пакетов, запустите
meteor --extra-packages bundle-visualizer --production
Отсюда вы можете увидеть, где можно добиться наибольших улучшений с помощью определенного импорта.
Динамический импорт (разделение кода)
Огромная проблема с веб-приложением Agolo заключалась в том, как оно обслуживало всю клиентскую базу кода для своих пользователей, независимо от того, с какой частью приложения они взаимодействуют. Например, пользователи на странице /home
загружали ресурсы со страницы /login
.
Благодаря динамическому импорту мы можем разделить наши маршруты по коду и предоставлять пользователям только соответствующие файлы. Если ваше веб-приложение создано с помощью Meteor, мы должны убедиться, что кодовая база соответствует стандартной файловой структуре Meteor. Если нет, можете пропустить эту часть.
Это явно или, по крайней мере, не указано явно в документации Meteor, но весь код в папке /client
будет объединен и проанализирован. Это верно, даже если файл Javascript нигде не импортируется и не используется (мы усвоили это на собственном горьком опыте).
По умолчанию ваше приложение Meteor уже должно иметь такую структуру. Но если нет, начните с рефакторинга вашего приложения Meteor, чтобы следовать этой файловой структуре.
/client main.html main.js /imports /api /startup /styles /ui /lib
Также не забудьте установить dynamic-imports
как пакет Meteor. Это позволяет нам асинхронно загружать наш импорт, который необходим для работы. Для этого запустите
meteor add dynamic-imports
Когда все готово, мы, наконец, можем приступить к реализации динамического импорта. Для этого в веб-приложении Agolo используется библиотека React-Loadable. Вы можете узнать больше о библиотеке из этого сообщения в блоге самого создателя здесь.
Начните с создания файла с именем dynamicImport.js
. Это вспомогательная функция для динамической загрузки наших маршрутов. В качестве альтернативы мы могли бы также использовать Loadable
из библиотеки React-Loadable напрямую. Однако вспомогательная функция может уменьшить количество повторяющегося кода и сделать ее более чистой.
Затем в файле настройки маршрута Route.js
обновите все импортированные компоненты маршрута в соответствии с новым соглашением о динамическом импорте.
Снова запустите Meteor с пакетом bundle-visualizer и флагом производства, чтобы проверить сокращение. Вы должны увидеть, что в пакете больше нет файлов маршрутов, которые не соответствуют местоположению URL-адреса.
Полученные результаты
С точки зрения эффективности и простоты реализации, стратегия Gzip лучше всего сработала для Agolo. На внедрение потребовалось меньше дня, но наша оценка производительности увеличилась примерно на 20 пунктов. Если вы этого не сделали, я настоятельно рекомендую вам начать как можно скорее.
Размер пакета
Размер сжатого пакета уменьшен с 3,4 МБ до 1,14 МБ.
Представление
Показатель производительности Lighthouse в Chrome увеличен с 10 до 61.
Скорость загрузки
Первая значимая краска уменьшена с 35 до 3,6 с.
Заключение
Реализация этих стратегий позволила Agolo стать веб-приложением выше среднего с рейтингом выше 50. Однако еще многое предстоит сделать. Agolo содержит весь клиентский код для своих статических страниц, просматриваемых в основном посетителями (дома, при регистрации, команде и т. Д.), Вместе с динамическими страницами, просматриваемыми только пользователями Agolo. Хотя это смягчается с помощью динамического импорта , мы все же планируем разделить эти две страницы.
Есть также много других стратегий для повышения производительности, таких как рендеринг на стороне сервера, отложенная загрузка, рефакторинг критически важного CSS в основной HTML и многое другое. Однако для наилучшего использования вашего времени и усилий в первую очередь следует реализовать эти три стратегии.
Удачи и удачного кодирования!
Спасибо Муди Саада и Прем Ганешкумар