Как я оптимизировал свой сайт на Angular


Введение

Создание приложений/сайтов с помощью Angular всегда имеет обратную сторону: размер пакета.
Последний напрямую влияет на скорость загрузки и пользовательский опыт нашего проекта.

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

Лично я придерживаюсь четырех шагов при создании приложений/сайтов.

  1. Проектирование
  2. Кодирование
  3. Сделать сайт отзывчивым
  4. Оптимизация

В этом посте мы сосредоточимся на последнем шаге.


Как я оптимизировал свой сайт на Angular

Я начну с проблем, с которыми я столкнулся, а затем расскажу, как я их решал.

1 — Визуальные проблемы

Следующая ссылка — это демонстрация моего сайта после 3-го шага.

Из этого видео мы можем выделить четыре визуальные проблемы:

1.1 — Визуальная проблема 1

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

1.2 — Визуальная проблема 2 & 3

Шрифт загружается долго, то же самое с картинкой пиццы.

1.3 — Визуальная проблема 4

Скорость загрузки изображений очень низкая.


2 — Невидимые проблемы

Давайте откроем dev-консоль и посмотрим, что происходит под капотом.

Из этого видео я могу выделить две проблемы

2.1 — Невидимая проблема 1

Полная загрузка сайта заняла 4,57 с, при 98 запросах и 5,4 МБ ресурсов. Чтобы представить эти цифры в перспективе, 3g интернету потребуется ~24 секунды, чтобы загрузить все ресурсы.

2.2 — Невидимая проблема 2

Для отображения картинки пиццы потребовалось ~1,07 с (0,689 с + 0,387 с), что означает, что пользователь видел сломанный слайдер в течение 1 секунды. То же самое касается и шрифта.

Вы можете спросить: Почему он выбрал пиццу из всех картинок?
Я отвечу вам другим вопросом:
Какую картинку вы видите первой, когда заходите на сайт?


Оценка маяка

Как я и ожидал, LCP (наибольшая содержательная картина) и CLS (кумулятивный сдвиг макета) плохие, из-за невидимой проблемы N°2 и визуальной проблемы N°1 соответственно, но, к удивлению, первая содержательная картина хорошая.

Размер пакета

Не так уж плохо, но мы можем сделать лучше.

ℹ️ Примечание: прежде чем объяснять и устранять указанные проблемы, давайте сначала оптимизируем размер пакета.


Улучшение размера пакета

Прежде чем начать, я хотел бы кое-что отметить:

  • ⚠️ Никогда не импортируйте CSS сторонних разработчиков в любой из ваших компонентов Angular, вместо этого используйте styles.css.

Есть много способов, как минимизировать размер пакета, но это не моя тема на сегодня, здесь я показываю, как «я» оптимизировал свой Angular сайт.

1 — Ленивая загрузка

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

  • У меня есть плагин под названием lightGallery, последний требуется только тогда, когда пользователь хочет открыть галерею изображений. Логично, что мы можем задержать его загрузку до тех пор, пока не будут загружены все более важные ресурсы сайта (например, изображения).

  • То же самое касается и Bootstrap, его JavaScript требуется только тогда, когда нам нужна интерактивность в нашем проекте, как, например: Открытие модала, Использование коллапса или карусели… Поэтому мы можем отложить его загрузку.

1.1 — Ленивая загрузка LightGallery

В следующем видео я подробно объясню процесс:

Код, который я использовал в видео :

// main.component.ts
let src = "https://jsdelivr.com"
window.onload = () => {
  let script = document.createElement("script")
  script.src = src
  script.async = true
  document.head.appendChild(script)
}
Вход в полноэкранный режим Выход из полноэкранного режима

1.2 — Ленивая загрузка Bootstrap

Тот же процесс происходит с Bootstrap, помните jsdelivr? Наберите в поисковике ‘bootstrap’ и :

Скопируйте ссылку и замените старую на новую.

ℹ️ Ps : Не забудьте удалить любой другой импортированный Bootstrap JavaScript.

1.3 — Размер пакета

Мы удалили (125.01 kB)

2 — Удаление неиспользуемых модулей

Мой сайт является одностраничным, несмотря на то, что установлен Angular routing. Чтобы исправить это, мне нужно всего лишь закомментировать AppRoutingModule в моем app.module.ts.

Теперь мне нужно заменить <router-outlet></router-outlet> на селектор родительского компонента, которым является app-main.

2.1 — Размер пакета

Мы исключили из первоначальной сборки в общей сложности (201,31 кБ).

Веб-сайт после уменьшения размера пакета.

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


Объяснение визуальной проблемы N°1

Этот сайт создан с помощью Bootstrap, и styles.css содержит Bootstrap's CSS. Причина этой проблемы в том, что Angular начал печатать сайт до того, как styles.css закончил загрузку, это означает, что у нас не было таблицы стилей для Bootstrap, пока styles.css не закончил загрузку.

Чтобы подтвердить это, мы можем попробовать заблокировать styles.css от загрузки вообще и посмотреть, получим ли мы те же результаты.

Да, те же самые.


Решение визуальной проблемы 1

Чтобы решить эту проблему, все мои critical CSS должны быть готовы, когда Angular начнет печататься. Критический CSS означает :

CSS, отвечающий за содержимое, которое сразу видно, когда мы открываем сайт.

или :

CSS первой страницы, которую вы видите при открытии сайта.

В моем случае :

  • Bootstrap CSS

Но поскольку у меня есть кнопки на первой странице, которые стилизованы с помощью пользовательского CSS, они также считаются критическими.

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

Чтобы продолжить, у нас есть Critical :

Теперь давайте вернемся к работе.

Во-первых, я создал SCSS файл с именем bootstrap.scss, и импортировал в него только нужный мне компонент

ℹ️ Ps : вы можете импортировать весь bootstrap, если хотите, потому что позже я объясню, как мы можем удалить неиспользуемый CSS с помощью PurgeCSS.

И я сделал то же самое с SwiperJs, Animations и моим пользовательским CSS

Затем я создал файл combined.scss и импортировал в него все SCSS-файлы, которые я только что создал.

Чтобы уточнить, вот список файлов, которые у вас должны быть:

ℹ️ Ps : не забудьте удалить старые импортированные CSS, например: не импортируйте Bootstrap в styles.scss и combined.scss.

После этого я перешел к angular.json, и в разделе styles[] :

{
  "projects": {
    "app": {
      "architect": {
        "build": {
          "options": {
            "styles": []
          }
        }
      }
    }
  }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Я добавил следующее:

{
  "input": "[YourPath]/combined.scss",
  "inject": false,
  "bundleName": "combined"
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем я открыл свой index.html и добавил приведенный ниже код в верхней части тега <head>.

 <!-- index.html -->
<link rel="preload" href="combined.css" as="style" />
<link rel="stylesheet" href="combined.css" />
Войти в полноэкранный режим Выйти из полноэкранного режима

Я сделал так, что когда пользователь заходит на сайт, первым ресурсом, который будет добавлен в очередь загрузки, будет combined.scss, это означает, что браузер начнет загрузку ресурсов моего сайта с combined.scss на вершине списка, таким образом, когда Angular начинает печать, критические CSS уже готовы.

Источник : https://developer.mozilla.org

Размер пакета

После сборки у меня появился раздел Lazy Chunk Files с моим файлом combined.css, в действительности я предварительно загружаю, а не лениво загружаю его.

Вы также можете заметить, что размер styles.css значительно уменьшился.

Теперь, благодаря PurgeCSS, я попробую уменьшить размер combined.css, удалив неиспользуемый CSS.


Установка PurgeCSS

В командной строке :

# command prompt
npm i -D purgecss
Войдите в полноэкранный режим Выйти из полноэкранного режима

После этого я создал файл с именем purgecss.config.js в корне моего проекта со следующими строками:

// purgecss.config.js
module.exports = {
  content: ["./dist/**/index.html", "./dist/**/*.js"],
  css: ["./dist/**/combined.css"],
  output: "./dist/[FOLDER]/combined.css",
  safelist: [/^swiper/],
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Ps : Замените [FOLDER] (в свойстве output).

Ps: Вы можете заметить, что я установил safelist в [/^swiper/], Это потому что я не хочу, чтобы PurgeCSS удалял любой SwiperJS CSS, потому что SwiperJS добавит некоторые CSS классы, о которых PurgeCSS не знает после выполнения страницы, и это заставит PurgeCSS удалить их.

Далее я открыл package.json, и отредактировал build из :

"build": "ng build"
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы

 "build": "ng build && npm run purgecss "
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем я создал новый скрипт с именем purgecss :

"purgecss": "purgecss -c purgecss.config.js",
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы пояснить, вот как должен выглядеть package.json

⚠️ Примечание :

Для сборки используйте npm run build вместо ng build, так PurgeCSS будет работать.

Результат

До и после использования PurgeCSS в combined.css :

Теперь давайте посмотрим на дерево загрузки:

Как я уже объяснял, combined.css теперь является первым файлом в очереди загрузки.
Недостатком этого метода является то, что теперь у нас есть две таблицы стилей (styles.css & combined.css), это означает еще один запрос к серверу и пару миллисекунд впустую. Позже я объясню, как я исправил эту небольшую проблему.

Маяк

Даже если Lighthouse говорит мне: «Ваш сайт идеален», он не прав на 100%,
Как насчет визуальной проблемы 2 & 3 & всех невидимых проблем?

Сайт после этого метода


Объяснение визуальной проблемы 2 & 3

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


Источник : blog.bluetriangle.com

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

Решение визуальной проблемы 2 & 3

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

Теперь я должен знать шрифт, используемый на первой странице. После этого, внутри <head> моего index.html я добавил :

 <!-- index.html -->
<link rel="preload" href="[YourPath]/DayburyRegular.woff2" as="font" type="font/woff2" crossorigin />
Войти в полноэкранный режим Выйти из полноэкранного режима

То же самое для изображения пиццы :

 <!-- index.html -->
<link rel="preload" href="[YourPath]/pizza.webp" as="image" />
Войти в полноэкранный режим Выйти из полноэкранного режима

Это должно выглядеть так :

⚠️ Примечание :

Перейдите к файлу CSS, содержащему ваш @font-face :

Если путь к вашему шрифту отличается от пути, который вы указали в вашем index.html, измените его на тот же, что и в index.html, Даже если они ведут к одному и тому же файлу, они должны быть написаны одинаково.

В противном случае браузер будет повторно загружать шрифт.

Для последнего шага браузеру нужно знать font-family моего предварительно загруженного шрифта, а это : 'DayburyRegular.woff2' до того, как Angular начнет печатать веб-сайт.

Когда мы говорим «до того, как Angular начнет печатать», мы говорим : combined.scss. Все, что мне нужно сделать сейчас, это перенести мой font-family в combined.scss.

Я создал файл с именем pre-fonts.scss и перенес свой шрифт из старого SCSS в новый.

После этого я импортировал pre-fonts.scss в combined.scss.

Результат

Давайте зайдем на сайт после этого исправления и проверим ресурсы.

Теперь шрифт и пицца больше не опоздают на вечеринку.


Объяснение визуальной проблемы 4

Как я объяснял в видео, когда мы лениво загружаем ресурсы, которые не видны в области просмотра, другие ресурсы (которые видны) загружаются быстрее, потому что теперь мы загружаем, например, 10 изображений, а не 100.

ℹ️ Глобально: нам нужно загружать только те изображения, которые действительно нужны, вместо того, чтобы загружать их заранее.

Решение визуальной проблемы 4

Решение заключается в реализации Lazy Loading. Существует множество методов и техник, но мой личный выбор — это lazysizes by Alexander Farkas.


Но прежде, поскольку все наши критические CSS находятся в combined.css, давайте посмотрим на мой styles.css.

Бедный файл, выглядит таким пустым, Шутки в сторону, поскольку все CSS внутри него некритичны, я лучше лениво загружу его тем же методом, который я использовал при ленивой загрузке LightGallery.

Сначала я перешел к angular.json, в разделе styles[] я отредактировал :

"src/styles.scss"
Войти в полноэкранный режим Выйти из полноэкранного режима

на

{
  "input": "src/styles.scss",
  "inject": false,
  "bundleName": "styles"
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь мне нужно загрузить styles.css после завершения загрузки всех ресурсов (как я это делал при ленивой загрузке LightGallery).

Итак, внутри моего main.component.ts, под ngAfterContentInit() и внутри window.onload я добавил :

var link = document.createElement("link")
link.rel = "stylesheet"
link.type = "text/css"
link.href = "styles.css"
document.head.appendChild(link)
Войти в полноэкранный режим Выход из полноэкранного режима


Теперь давайте вернемся к проблеме. Я бы с удовольствием объяснил вам, как я лениво загрузил свой сайт, но этот пост уже достаточно длинный, к тому же, это не основная тема. Поэтому я перейду непосредственно к результатам, однако, я планирую написать подробное пошаговое руководство и разместить ссылку на него прямо здесь.

Результат

Маяк

Миссия выполнена ✅

ℹ️ Примечание: Пока я решал свои визуальные проблемы, все мои невидимые проблемы тоже были решены:

  • Невидимая проблема 1 была устранена, когда мы решили визуальную проблему 4, (когда я лениво загружал сайт с lazysizes)

  • Невидимая проблема 2 была решена, когда мы решили визуальную проблему 2 & 3 (когда я предварительно загрузил шрифт и картинку пиццы).

Вы можете посетить сайт после этого последнего шага (:

Дубль

  • Когда ваш сайт начнет печататься, убедитесь, что все критические CSS готовы.

  • Если необходимо, предварительно загрузите некоторые ресурсы (основные), чтобы улучшить UX (как мы сделали с картинкой пиццы и шрифтом).

  • Всегда, как Всегда, лениво загружайте изображения, и, если возможно, лениво загружайте некритичные JS & CSS.

  • Старайтесь устанавливать минимум сторонних библиотек, а бесполезные удаляйте.

  • Всегда открывайте dev-консоль, анализируйте и расставляйте приоритеты в порядке использования ресурсов.


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

ℹ️ Примечание: я старался быть максимально дружелюбным к новичкам, поэтому в некоторых случаях я покажусь вам немного повторяющимся и скучным.

Внести свой вклад

Исправьте этот пост на github

Оцените статью
devanswers.ru
Добавить комментарий