Как ускорялся фронтенд
ponominalu.ru
Pagespeed Insight
Сухие цифры
Как было: Mobile/Desktop
Как стало: Mobile/Desktop
Важные показатели скорости загрузки страницы


CLS (Cumulative Layout Shift) —
показатель смещения элементов во
время загрузки страницы.


LCP (Largest Contentful Paint) —
определяет время, за которое браузер
отрисовывает самый крупный видимый
объект в области просмотра.


Подробнее:


https://web.dev/lcp/


https://web.dev/cls/


https://developers.google.com/speed/
Что мы сделали
Оптимизация сети: браузер
Handshak
e

При большом числе внешних
соединений время загрузки
значительно увеличивается.


<link rel=“dns-prefetch”> - для
важных внешних ресурсов


<link rel="preconnect"> - для
ускорения общения по API


<script async> - для прочих скриптов
Static resource
s

Асинхронная загрузка
изображений с vue-lazyload

 Загрузка шрифтов от Google
Fonts с флагом ?display=swap
Гидратация
Гидратация относится к процессу на стороне клиента, в течение которого Vue
берёт статический HTML, отправленный сервером, и превращает его в
динамический DOM, который может реагировать на изменения данных на
стороне клиента. Мы решили использовать vue-lazy-hydration для правильного
соответствия виртуального DOM и сгенерированного сервером реального DOM.


Итогом получается совмещение легкого нужного для SEO HTML, который
насыщается функциональностью уже на стороне клиента. Это позволяет
заметно уменьшить вложенность узлов, что благоприятно сказывается на
скорости первоначального парсинга.
Оптимизация сети: сервер
HTTP2 дает большой прирост производительности при множестве
небольших запросов на один домен. Поэтому мы перенесли часть
субдоменов на основной домен.


Основные наши запросы: JS-чанки, изображения и REST API.


Вместо колбэков с самого начала использовали промисы. Это позволило
достаточно легко распараллелить последовательные запросы используя
Promise.all
Серверный кэш
У нас изоморфное приложение с четким
разделением серверного и клиентского JavaScript.
Вся логика реализована на API и поэтому генерация
страниц не использует кукисы.

Используется кэш nginx через заголовки:


- cache-control


- expires


Версионирование каждой страницы и чанка
делается путем добавления к пути версии билда:


…?build=00023110


После каждого обновления проекта номер сборки
семантично инкрементируется что упрощает
тестирование сборки.
Оптимизация сборки: Webpack
1) Импортирование компонентов по требовани
ю



Было:

import PnElement from '~/components/PnElement.vue'

…

components: { PnElement }



Стало:
 

components: {

PnElement: () => import (/* webpackChunkName:'PnFooter' */‘@/components/footer/PnFooter')

}



2) Использование webpack с esm модулями для treeshaking
Совмещение ES5 и ES6 билдов
Современные браузеры уже хорошо интерпретируют ES6 код, поэтому использование
полифилов в сборке лишь утяжеляет JavaScript. Мы реализовали два вида сборки:


1) ES5 для старых браузеров:

<script nomodule src="/_nuxt/commons.f359cd40fae02fa6fd5c.js?build=00023110" defer></
script> - 298 kB


2) ES6 для новых браузеров:


<script type="module" src="/_nuxt/commons.d0f883fa1e05a3f63df2.js?build=00023110"
defer></script> - 271 kB


У нас HighLoad приложение, поэтому чтобы лишний раз не нагружать логикой сервера,
детектирование ES6 браузеров мы сделали на клиенте.
Оптимизация CSS
1) Убрали из проекта bootstrap и перенесли в scoped свою Дизайн
систему.


2) Удалили лишние анимация, что привело к повышению скорости
первичной загрузки.


3) Оптимизировали виртуальный DOM. Vue до 3 версии проходил по
всем нодам и сверял их изменения. Поэтому мы вынесли тяжелые
куски шаблонов в глупые компоненты Storybook.
Что не успели?
• Произвести отказ от тяжелых библиотек
moment.js и axios


• Перевести код на Vue 3

• Удалить старый bootstrap легаси

• Ускорить iframe через loading:lazy

• Отрефакторить тяжелые миксины для
trhee-shaking’а. А именно: заменить
export default на множество export.



Ускорение фронтенда ponominalu.ru

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
    Важные показатели скоростизагрузки страницы CLS (Cumulative Layout Shift) — показатель смещения элементов во время загрузки страницы. LCP (Largest Contentful Paint) — определяет время, за которое браузер отрисовывает самый крупный видимый объект в области просмотра. Подробнее: https://web.dev/lcp/ https://web.dev/cls/ https://developers.google.com/speed/
  • 6.
  • 7.
    Оптимизация сети: браузер Handshak e Прибольшом числе внешних соединений время загрузки значительно увеличивается. <link rel=“dns-prefetch”> - для важных внешних ресурсов 
 <link rel="preconnect"> - для ускорения общения по API 
 <script async> - для прочих скриптов Static resource s Асинхронная загрузка изображений с vue-lazyload Загрузка шрифтов от Google Fonts с флагом ?display=swap
  • 8.
    Гидратация Гидратация относится кпроцессу на стороне клиента, в течение которого Vue берёт статический HTML, отправленный сервером, и превращает его в динамический DOM, который может реагировать на изменения данных на стороне клиента. Мы решили использовать vue-lazy-hydration для правильного соответствия виртуального DOM и сгенерированного сервером реального DOM. Итогом получается совмещение легкого нужного для SEO HTML, который насыщается функциональностью уже на стороне клиента. Это позволяет заметно уменьшить вложенность узлов, что благоприятно сказывается на скорости первоначального парсинга.
  • 9.
    Оптимизация сети: сервер HTTP2дает большой прирост производительности при множестве небольших запросов на один домен. Поэтому мы перенесли часть субдоменов на основной домен. 
 Основные наши запросы: JS-чанки, изображения и REST API. Вместо колбэков с самого начала использовали промисы. Это позволило достаточно легко распараллелить последовательные запросы используя Promise.all
  • 10.
    Серверный кэш У насизоморфное приложение с четким разделением серверного и клиентского JavaScript. Вся логика реализована на API и поэтому генерация страниц не использует кукисы. Используется кэш nginx через заголовки: 
 - cache-control 
 - expires Версионирование каждой страницы и чанка делается путем добавления к пути версии билда: 
 …?build=00023110 
 После каждого обновления проекта номер сборки семантично инкрементируется что упрощает тестирование сборки.
  • 11.
    Оптимизация сборки: Webpack 1)Импортирование компонентов по требовани ю 
 Было:
 import PnElement from '~/components/PnElement.vue'
 …
 components: { PnElement }
 
 Стало: components: {
 PnElement: () => import (/* webpackChunkName:'PnFooter' */‘@/components/footer/PnFooter')
 } 
 2) Использование webpack с esm модулями для treeshaking
  • 12.
    Совмещение ES5 иES6 билдов Современные браузеры уже хорошо интерпретируют ES6 код, поэтому использование полифилов в сборке лишь утяжеляет JavaScript. Мы реализовали два вида сборки: 1) ES5 для старых браузеров: 
<script nomodule src="/_nuxt/commons.f359cd40fae02fa6fd5c.js?build=00023110" defer></ script> - 298 kB 2) ES6 для новых браузеров: 
 <script type="module" src="/_nuxt/commons.d0f883fa1e05a3f63df2.js?build=00023110" defer></script> - 271 kB У нас HighLoad приложение, поэтому чтобы лишний раз не нагружать логикой сервера, детектирование ES6 браузеров мы сделали на клиенте.
  • 13.
    Оптимизация CSS 1) Убралииз проекта bootstrap и перенесли в scoped свою Дизайн систему. 2) Удалили лишние анимация, что привело к повышению скорости первичной загрузки. 3) Оптимизировали виртуальный DOM. Vue до 3 версии проходил по всем нодам и сверял их изменения. Поэтому мы вынесли тяжелые куски шаблонов в глупые компоненты Storybook.
  • 14.
    Что не успели? •Произвести отказ от тяжелых библиотек moment.js и axios • Перевести код на Vue 3 • Удалить старый bootstrap легаси • Ускорить iframe через loading:lazy • Отрефакторить тяжелые миксины для trhee-shaking’а. А именно: заменить export default на множество export.