Как оптимизировать приложения Angular

Stepan Mikulov

Administrator
Команда форума
Angular - самый популярный фреймворк для создания одностраничных веб-приложений. Хотя я сказал об одной странице, это не обязательно означает, что ваше приложение может содержать только одну страницу. Вы можете создать веб-сайт с десятками страниц с помощью Angular. Сам фреймворк (последние версии) хорошо оптимизирован благодаря замечательной команде и сообществу, однако, когда дело касается производительности, мы всегда должны думать о нескольких вещах, которые могут сделать наше приложение быстрым и плавным.

# 1 Оптимизация основного пакета с помощью отложенной загрузки
Когда мы создаем наше приложение в производственной среде без отложенной загрузки, скорее всего, мы увидим эти файлы, созданные в папке dist.

polyfills.js
scripts.js
runtime.js
styles.css
main.js

polyfills.js предназначен для обеспечения совместимости нашего приложения с различными браузерами. Потому что мы пишем код с новейшими функциями, и не все браузеры поддерживают такие функции.
scripts.js содержит скрипты, которые мы объявляем в разделе скриптов файла angular.json.

"scripts": [
"myScript.js",
]

runtime.js - это загрузчик веб-пакетов. Этот файл содержит утилиты webpack, необходимые для загрузки других файлов.
styles.css содержит все стили, которые мы объявляем в разделе стилей файла angular.json.

"styles": [
"src/styles.css",
"src/my-custom.css"
],

main.js содержит весь наш код, включая компоненты (коды ts, html и css), каналы, директивы, службы и все другие импортированные модули (включая сторонние).
Как вы можете видеть, со временем файл main.js будет становиться все больше и больше, что является проблемой, поскольку для просмотра веб-сайта браузеру необходимо загрузить файл main.js, выполнить и отобразить на странице, что не только может быть сложной задачей для мобильных устройств. пользователи с медленным интернетом, но также и для настольных компьютеров.
Самый простой способ решить эту проблему - разбить ваше приложение на несколько ленивых модулей. Когда мы используем ленивые модули для каждого модуля, angular генерирует свой собственный фрагмент, и он не загружается до тех пор, пока не понадобится (обычно путем активации маршрута).
Чтобы продемонстрировать это, я создал два компонента: app.component и second.component. Оба находятся в app.module, так что здесь нет ничего ленивого. App.component очень прост и имеет две кнопки для перехода к Second.component и обратно к App.component.

Однако второй компонент содержит в шаблоне очень большой текст (около 1 Мб).

Image for post



Поскольку нет лени, когда мы создаем наше приложение, мы получаем большой main.js, который содержит весь код как из app.component, так и из second.component.
Теперь на вкладке сети инструментов chrome dev мы видим, что действительно main.js слишком велик (1,3 мб)

Image for post


Поскольку нет лени, когда мы создаем наше приложение, мы получаем большой main.js, который содержит весь код как из app.component, так и из second.component.
Теперь на вкладке сети инструментов chrome dev мы видим, что действительно main.js слишком велик (1,3 мб)

Image for post

И только когда мы переходим на вторую страницу, мы видим, что загружен новый файл (1 МБ).

Image for post


Однако загрузка каждой части таким образом также повлияет на производительность, поскольку начальная навигация будет медленнее. К счастью, Agular предоставляет способ решить эту проблему с помощью PreloadingStrategy. Мы можем сказать, что Angular загружает наш основной модуль (main.js), и когда он полностью загружен и запущен, только после этого загружать другие ленивые модули в фоновом режиме, поэтому, когда пользователи переходят на ленивые страницы, все уже будет загружено. Пример кода для предварительной загрузки всех модулей

import { PreloadAllModules, RouterModule } from '@angular/router';RouterModule.forRoot(
[
{
path: 'second',
loadChildren: './second/second.module#SecondModule' }
], {preloadingStrategy: PreloadAllModules})

Поэтому всегда старайтесь использовать как можно больше ленивых модулей с какой-либо стратегией предварительной загрузки. Это сохранит ваш main.js небольшим, что означает более быструю загрузку и рендеринг главной страницы.

# 2 Отладочные пакеты с помощью анализатора пакетов Webpack

Даже если после разделения логики приложения на множество ленивых модулей вы получите большой основной пакет (в качестве «большого» я лично считаю более 1 МБ для приложений малого и среднего размера), вы можете продолжить оптимизацию с помощью Webpack Bundle Analyzer. Этот пакет npm позволяет визуализировать размер выходных файлов webpack с помощью интерактивной масштабируемой древовидной карты. Прежде всего, установите плагин как зависимость разработчика в вашем проекте angular.

npm install --save-dev webpack-bundle-analyzer

Затем измените файл package.json, добавив эту строку в раздел скриптов.

"bundle-report": "ng build --prod --stats-json && webpack-bundle-analyzer dist/stats.json"

Обратите внимание, что dist / stats.json может быть другим в вашем проекте. Например, если ваши файлы пакета созданы в dist / browser, вам необходимо изменить команду как dist / browser / stats.json.

Наконец запустить

npm run bundle-report

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


Image for post



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

# 3 Создайте несколько небольших общих модулей
Считается лучшей практикой иметь общие модули для DRY, но иногда общий модуль также может становиться все больше и больше. Например, если у нас есть SharedModule, который содержит много других модулей / компонентов / каналов, импорт такого модуля в app.module увеличит размер пакета main.js, потому что мы будем импортировать не только то, что нужно основному модулю, но и все другие ненужные вещи. который поставляется с SharedModule. Чтобы избежать этого, мы можем создать еще один общий модуль, HomeSharedModule, который будет содержать только те компоненты, которые необходимы основному модулю и его компонентам.

Лучше иметь несколько общих модулей, чем один большой общий модуль.

# 4 Используйте отложенную загрузку для изображений, которые не отображаются на странице
Когда мы загружаем нашу главную страницу в первый раз, у нас могут быть изображения, которые не видны пользователю (не в области просмотра). Пользователь должен прокрутить вниз, чтобы увидеть изображения. Однако изображения загружаются сразу, когда мы загружаем страницу, и если у нас много изображений, это действительно может повлиять на производительность. Чтобы решить эту проблему, мы можем лениво загружать изображения, загружать их только тогда, когда пользователи добираются до них. Существует JavaScript API - Intersection Observer API, который позволяет легко реализовать ленивую загрузку контента. Кроме того, мы можем создать директиву для повторного использования. Вот хорошая статья об этом.

# 5 Используйте виртуальную прокрутку для больших списков
В версии 7 фреймворка появилась виртуальная прокрутка в CDK. Виртуальная прокрутка загружает и выгружает элементы из DOM на основе видимых частей списка, что делает наше приложение чрезвычайно быстрым.

Image for post

Instead of loading and displaying full list, we can display only few items that are visible at that time

# 6 Используйте FOUT вместо FOIT для шрифтов
На большинстве веб-сайтов мы видим нестандартные красивые шрифты, а не обычные шрифты. Однако для использования пользовательского шрифта или шрифта, предоставляемого другой службой, браузер должен загружать и анализировать этот шрифт, когда пользователь посещает нашу страницу. Есть два сценария, что произойдет, если мы будем использовать пользовательские шрифты, предоставляемые сторонними сервисами, такими как Google Fonts.
1. Браузер ожидает загрузки шрифта, его анализа и только после этого отображает текст на странице. Текст на странице будет невидимым, пока шрифт не будет загружен и проанализирован. Это FOIT, или вспышка невидимого текста.
2. Браузер изначально отображает текст обычным шрифтом, а также пытается получить внешние стили шрифта. После загрузки и анализа он заменит обычный шрифт на наш собственный. Текст на странице будет отображаться обычным шрифтом, при этом, если браузер загрузит и проанализирует внешний шрифт, шрифты будут заменены. Это FOUT, или вспышка не стилизованного текста
Большинство браузеров используют FOIT, и только Internet Explorer использует FOUT. Чтобы исправить это, мы можем использовать дескриптор font-display для @ font-face и сообщить браузеру, хотим ли мы использовать обычный шрифт, а затем поменять местами или оставить текст невидимым. Вы также можете прочитать эту статью, в которой объясняется, как работают шрифты и в каких случаях вам нужны FOIT и FOUT.

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

 
Сверху