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:

  1. Клиент (браузер) отправит HTTP-запрос с vary: Accept-Encoding в его заголовке. Это означает, что браузер поддерживает сжатие.
  2. Nginx получает запрошенную полезную нагрузку с веб-сервера.
  3. Nginx проверяет полезную нагрузку и выбирает, сжимать ее с помощью Gzip или нет.
  4. 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 и многое другое. Однако для наилучшего использования вашего времени и усилий в первую очередь следует реализовать эти три стратегии.

Удачи и удачного кодирования!

Спасибо Муди Саада и Прем Ганешкумар