Как вы оптимизируете загрузку и производительность Angular-приложения на проде?
Оптимизация загрузки и производительности Angular-приложения на продакшене требует комплексного подхода, охватывающего архитектуру, сборку, загрузку ресурсов, работу с данными и стратегию рендеринга. Ниже перечислены ключевые практики, применяемые для ускорения загрузки и повышения производительности.
1. Production сборка (ng build --configuration production)
Angular CLI при прод-сборке:
-
Минифицирует HTML, CSS, JS;
-
Удаляет console.log и debugger;
-
Применяет tree-shaking;
-
Включает Ahead-of-Time (AOT) компиляцию;
-
Генерирует файлы с хешами для кэширования.
2. Lazy Loading модулей
Lazy loading позволяет загружать части приложения только по требованию.
const routes: Routes = \[
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.module').then((m) => m.AdminModule)
}
\];
-
Уменьшает размер initial bundle;
-
Улучшает Time to Interactive (TTI).
3. Preloading Strategy
Чтобы загружать ленивые модули после начальной загрузки, применяют стратегию preloading:
RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
});
Или создают собственную стратегию на основе пользовательской логики.
4. Использование Standalone компонентов
С Angular 14+ можно использовать standalone-компоненты без модулей:
@Component({
standalone: true,
imports: \[CommonModule\],
template: \`<p>Hello</p>\`
})
export class HelloComponent {}
Уменьшается связность, ускоряется загрузка, снижается объем кода.
5. ChangeDetectionStrategy.OnPush
По умолчанию Angular использует ChangeDetectionStrategy.Default, что может привести к лишнему пересчету.
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
-
Проверка запускается только при изменении @Input();
-
Уменьшает нагрузку на зону детектирования.
6. TrackBy для ngFor
Чтобы избежать перерисовки всех элементов при изменении массива:
<li \*ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
trackById(index: number, item: Item) {
return item.id;
}
Сохраняет DOM-элементы и уменьшает работу рендера.
7. Оптимизация изображений
-
Использовать ngOptimizedImage (Angular 15+);
-
WebP/AVIF-форматы;
-
Ленивая загрузка (loading="lazy");
-
Использовать CDN и srcset.
8. Code splitting и dynamic imports
Разделение кода на чанки для загрузки по мере необходимости:
async loadModule() {
const module = await import('./some-heavy.module');
// используем module.SomeComponent
}
Это снижает размер основного бандла.
9. Удаление неиспользуемого кода (Tree Shaking)
-
Не импортировать весь модуль, если нужен один компонент;
-
Избегать реэкспорта всего модуля (SharedModule);
-
Использовать ES модули, не CommonJS;
-
Строгий режим в tsconfig улучшает tree-shaking.
10. Оптимизация сторонних библиотек
-
Не подключать библиотеки целиком (import { map } from 'rxjs', а не rxjs/operators);
-
Проверять размер через webpack-bundle-analyzer;
-
Использовать легковесные аналоги (lodash-es, date-fns).
11. Использование defer и async
При вставке скриптов:
<script src="some-lib.js" defer></script>
Скрипты загружаются асинхронно, не блокируя рендеринг страницы.
12. Уменьшение количества зон (Zone.js)
Angular 16+ поддерживает signals и zone-less режим.
Это позволяет избежать лишних перерисовок и повысить производительность.
13. Серверный рендеринг (Angular Universal)
-
Быстрая первая отрисовка (First Contentful Paint);
-
SEO-дружественность;
-
Пререндеринг с ng run app:prerender.
14. Управление памятью и подписками
-
Всегда отписывайтесь от Observable:
-
takeUntil;
-
async pipe;
-
untilDestroyed.
-
Неправильные подписки приводят к утечкам памяти и деградации производительности.
15. Оптимизация формы и реактивной логики
-
Использовать FormControl вне шаблона;
-
Избегать сложных реакций в form.valueChanges;
-
Использовать distinctUntilChanged, debounceTime для throttle.
16. HTTP кэширование
- Реализовать стратегию кэширования на уровне сервиса:
@Injectable({ providedIn: 'root' })
export class ApiService {
private cache = new Map<string, Observable<any>>();
getData(url: string): Observable<any> {
if (!this.cache.has(url)) {
this.cache.set(url, this.http.get(url).pipe(shareReplay(1)));
}
return this.cache.get(url)!;
}
}
- Использовать браузерный Cache-Control и CDN.
17. Service Workers и PWA
-
Использовать Angular PWA (ng add @angular/pwa);
-
Service Worker кэширует статику;
-
Offline поддержка;
-
Precache и runtime-кэширование данных и API.
18. Анализ и инструменты
-
source-map-explorer и webpack-bundle-analyzer — анализ размеров;
-
Lighthouse, PageSpeed Insights — метрики производительности;
-
Chrome DevTools — FPS, memory, layout shift, JS профайлинг.
19. Inlining critical CSS
CLI в режиме production автоматически выносит critical CSS в <head>, чтобы избежать FOUC и ускорить рендеринг.
20. HTTP/2 + CDN + GZIP/Brotli
-
Активировать HTTP/2 для одновременной загрузки;
-
Использовать CDN (Cloudflare, Akamai);
-
Сжатие GZIP/Brotli для всех ресурсов.
21. Динамическая подгрузка i18n и переводов
-
Загрузка только нужных переводов (ngx-translate, @angular/localize);
-
Lazy loading модулей с соответствующим языком.
22. Пререндеринг роутов
ng run app:prerender
-
Генерация статических HTML для всех маршрутов;
-
Идеально для маркетинговых страниц, SEO.
23. Кэширование с версионированием
-
Angular CLI генерирует файлы с хешами (main.[hash].js);
-
Браузер кэширует до тех пор, пока хеш не изменится;
-
Это уменьшает сетевую нагрузку при повторных визитах.
Оптимизация Angular-приложения — это не единоразовое действие, а постоянный процесс, который включает архитектурные решения, работу с данными, настройку сборки и эффективное использование возможностей Angular CLI и Webpack.