Оптимизация моего проекта React Playground для большей прогрессивности

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

Прогрессивные веб-приложения похожи на пиццу. Вы просто не можете не любить их особенности. Так почему бы не попытаться стать немного более прогрессивным с моим проектом игровой площадки.

Первый аудит

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

Ой! 29/100.

Итак, что мы можем с этим поделать?

Начнем сверху.

Эй, пойдем!

Добавление Service Workers для базовой офлайн-поддержки (+14 баллов)

Скрипт service worker выполняется в фоновом режиме в отдельном потоке. После регистрации и установки он может прослушивать события, генерируемые сетевыми запросами.
У него нет доступа к модели DOM, но он может перехватывать эти сетевые запросы, а также выполнять собственные запросы на выборку и предварительное кэширование данных.

Из соображений безопасности Service Worker может быть зарегистрирован и установлен только тогда, когда страницы используют https. Единственное исключение, конечно, если страницы обслуживаются на локальном хосте в процессе разработки.

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

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

Для получения исчерпывающей информации о необходимых соображениях для использования сервисными работниками в реальном мире я рекомендую этот отличный доклад Антони Хьюге Вивеса.

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

Я нашел эту статью о сервис-воркерах (особенно часть об их убийстве до их 24-часового цикла обновления) очень полезной.

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

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

  • Очевидно, мне пришлось явно включить те активы, которые не обрабатываются webpack. В моем случае я решил, что не хочу, чтобы мои аудиофайлы обрабатывались загрузчиками файлов веб-пакета, и просто поместил их в общую папку.
    Поэтому мне пришлось включить их в конфигурацию плагинов, а также мои index.html, который также не обрабатывается веб-пакетом.
  • offline-plugin использует нашего старого придурка Application Cache в качестве запасного варианта, если на клиенте нет поддержки сервис-воркеров. Так что предоставить ему соответствующий файл asset-manifest.json было бы неплохо.

Хорошо yarn add -D offline-plugin и добавить его и его конфигурацию в файл webpack.config.js.

//webpack.config.js
module.exports = { 
// ...
plugins[
new OfflinePlugin({
      publicPath: '/',
      externals: externalsUrls,
      ServiceWorker: {
    navigateFallbackURL: '/'
  }}), 
//...
],
}

И добавить его в файл записи

// index.js
import * as OfflinePluginRuntime from 'offline-plugin/runtime';
OfflinePluginRuntime.install();

Ладно, поехали снова:

Уже лучше, но все еще впереди!

Добавление манифеста веб-приложения (+31 балл)

Манифест веб-приложения позволит пользователям добавлять его на свой рабочий стол и позволяет указать внешний вид приложения, когда оно используется вне браузера.

Связать manifest.json довольно просто, и создать базовый манифест также очень просто. Это manifest.json для моего проекта игровой площадки:

//manifest.json
{
“name”: “KlangBlocks”,
“short_name”: “KlangBlocks”,
“start_url”: “.”,
“display”: “standalone”,
“theme_color”: “#002635”,
“background_color”: “#002635”,
“description”: “Here to make you think about death and get sad and stuff.”,
“icons”: [{
“src”: “icons/64.png”,
“sizes”: “64x64”,
“type”: “image/png”
}, {
“src”: “icons/128.png”,
“sizes”: “128x128”,
“type”: “image/png”
}, {
“src”: “icons/192.png”,
“sizes”: “192x192”,
“type”: “image/png”
},
{
“src”: “icons/384.png”,
“sizes”: “384x384”,
“type”: “image/png”
},
{
“src”: “icons/512.png”,
“sizes”: “512x512”,
“type”: “image/png”
}]
}

и ссылка в моем index.html
<link rel=”manifest” href=”%PUBLIC_URL%/manifest.json”>

Google рекомендует включать как минимум 192x192 icon to ensure providing the appropriate pixel density for larger displays. But to be safe it's recommended to provide icons up to a size of 512x512 pixels.

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

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

Нет, мы можем просмотреть манифест приложения на вкладке «Приложение» в devtools. Давайте нажмем «Добавить на рабочий стол» и посмотрим, все ли в порядке.

И вуаля. Красиво не правда ли? (;

Где мы сейчас находимся?

Лучше, но если есть оценки с зеленым цветом, мы хотим, чтобы (:

Использование require.ensure() для ленивой загрузки модулей/разбиения кода для повышения производительности

До сих пор мы не касались реального кода приложения.
По-моему, это довольно печально.
Я предполагаю, что большая часть нашего bundle.js должна быть отнесена к библиотеке Tone.js, которая делает всевозможные удивительные вещи с API веб-аудио (например, предоставляет действительно умное решение для планирования в сочетании с изменением/наращиванием общего темпа, что требует большого творчества из-за внутренней работы Web Audio Clock).

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

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

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

Анализ файла stats.json веб-пакета подтверждает наше предположение.

Я не буду вдаваться в подробности о require.ensure(), потому что скоро он будет полностью заменен на import().

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

Это консольный вывод нашего скрипта сборки:

Creating an optimized production build…
Compiled successfully.
File sizes after gzip:
101.51 KB (-42.55 KB) build/static/js/main.cae42e7d.js
 43.23 KB build/static/js/loop.591c7667.chunk.js
 2.74 KB build/sw.js

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

Делиться чем-то даже с теми, кто не говорит на одном языке (+12 баллов)

Хорошо, это приложение React, так что без JavaScript нам будет тяжело.

Но эй, я стараюсь изо всех сил ❤

Вот что вы видите, если не можете выполнить JavaScript:

https://noscript-but-love.surge.sh/

Что Lighthouse может сказать обо всем этом?

Не будем жадничать сегодня. Эй, он зеленый ❤

Вывод

Было довольно легко улучшить оценку Lighthouse, но мы должны помнить о нескольких вещах:

  • PWA — это не какие-то баллы, а улучшение опыта для реальных людей. Так что к аудиту Lighthouse следует относиться с долей скептицизма.
  • Не было ни COR, ни существующей кодовой базы, ни 3xx-запросов, ни аутентификации пользователя, нам нужны были почти все данные с самого начала, а просто предварительно загрузить их без разбора было не слишком сложно.
  • Оценка не так уж плоха, но во многих аспектах приложение все еще не очень прогрессивно, например, мы могли бы значительно улучшить скорость восприятия, внедрив оболочку приложения и/или визуализировав некоторый фиктивный скелет перед инициализацией наших реальных данных.

Уроки выучены

Предоставление некоторого контента даже пользователям без поддержки JavaScript поначалу может показаться почти неразумным, но не должны ли мы пытаться общаться со всеми, кто пытается связаться с нами, даже если мы не говорим на одном языке?
Может быть, прогрессивное улучшение должно касаться не только Интернета?