- Введение
- Как я оптимизировал свой сайт на Angular
- 1 — Визуальные проблемы
- 1.1 — Визуальная проблема 1
- 1.2 — Визуальная проблема 2 & 3
- 1.3 — Визуальная проблема 4
- 2 — Невидимые проблемы
- 2.1 — Невидимая проблема 1
- 2.2 — Невидимая проблема 2
- Оценка маяка
- Размер пакета
- Улучшение размера пакета
- 1 — Ленивая загрузка
- 1.1 — Ленивая загрузка LightGallery
- 1.2 — Ленивая загрузка Bootstrap
- 1.3 — Размер пакета
- 2 — Удаление неиспользуемых модулей
- 2.1 — Размер пакета
- Объяснение визуальной проблемы N°1
- Решение визуальной проблемы 1
- Размер пакета
- Установка PurgeCSS
- Результат
- Маяк
- Объяснение визуальной проблемы 2 & 3
- Решение визуальной проблемы 2 & 3
- Результат
- Объяснение визуальной проблемы 4
- Решение визуальной проблемы 4
- Результат
- Маяк
- Дубль
- Внести свой вклад
Введение
Создание приложений/сайтов с помощью Angular всегда имеет обратную сторону: размер пакета.
Последний напрямую влияет на скорость загрузки и пользовательский опыт нашего проекта.
Даже если мы, наконец, уменьшили размер пакета, есть и другие моменты, которые необходимо проверить, чтобы получить идеальный сайт.
Лично я придерживаюсь четырех шагов при создании приложений/сайтов.
- Проектирование
- Кодирование
- Сделать сайт отзывчивым
- Оптимизация
В этом посте мы сосредоточимся на последнем шаге.
Как я оптимизировал свой сайт на 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